Kew*_*ewl 70 python python-3.x iterable-unpacking
我正在阅读一些旧代码,试图理解它的作用,我偶然发现了这个奇怪的声明:
*x ,= p
Run Code Online (Sandbox Code Playgroud)
p是这个上下文中的列表.我一直试图弄清楚这句话的作用.据我所知,它只是设置x为的值p.例如:
p = [1,2]
*x ,= p
print(x)
Run Code Online (Sandbox Code Playgroud)
只是给
[1, 2]
Run Code Online (Sandbox Code Playgroud)
这有什么不同x = p吗?知道这个语法在做什么吗?
Eug*_*ash 74
*x ,= p基本上是x = list(p)使用扩展可迭代解包的混淆版本.之后的逗号x需要使赋值目标成为元组(尽管也可以是列表).
*x, = p 是从不同的x = p,因为前者创建一个副本的p,而后者创建了一个(即一个新的列表)引用到原始列表.为了显示:
>>> p = [1, 2]
>>> *x, = p
>>> x == p
True
>>> x is p
False
>>> x = p
>>> x == p
True
>>> x is p
True
Run Code Online (Sandbox Code Playgroud)
zon*_*ndo 45
这是Python 3.0(PEP 3132)中引入的一项功能.在Python 2中,您可以执行以下操作:
>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3
Run Code Online (Sandbox Code Playgroud)
Python 3对此进行了扩展,以便一个变量可以包含多个值:
>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]
Run Code Online (Sandbox Code Playgroud)
因此,这就是这里使用的内容.但是,不是两个变量来保存三个值,而是只有一个变量可以获取列表中的每个值.这不同于x = p因为x = p只是意味着它x的另一个名称p.但是,在这种情况下,它是一个新的列表,恰好在其中具有相同的值.(你可能对"Least Astonishment"和Mutable Default Argument感兴趣)
产生这种效果的另外两种常见方法是:
>>> x = list(p)
Run Code Online (Sandbox Code Playgroud)
和
>>> x = p[:]
Run Code Online (Sandbox Code Playgroud)
从Python 3.3开始,list对象实际上有一个用于复制的方法:
x = p.copy()
Run Code Online (Sandbox Code Playgroud)
切片实际上是一个非常相似的概念.然而,正如nneonneo指出的那样,它仅适用于支持切片的列表和元组等对象.但是,您提到的方法适用于任何可迭代的:字典,集合,生成器等.
Jim*_*ard 14
你应该总是扔掉这些dis东西,看看它会给你带来什么; 你会看到*x, = p实际上有什么不同于x = p:
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
Run Code Online (Sandbox Code Playgroud)
而,简单的赋值语句:
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
Run Code Online (Sandbox Code Playgroud)
(剥离不相关的None回报)
正如您所看到UNPACK_EX的,这些之间的操作码不同; 它被记录为:
使用已加星标的目标实现赋值:将TOS(堆栈顶部)中的可迭代解包为单个值,其中值的总数可以小于可迭代中的项数:其中一个新值将是所有值的列表剩下的物品.
这就是为什么,正如尤金指出的那样,你得到了一个名称所x引用的新对象,而不是对已经存在的对象的引用(就像这样x = p).
*x,看起来很奇怪(那里有额外的逗号和所有)但这里需要它.左侧必须是元组或列表,并且由于在Python中创建单个元素元组的怪癖,您需要使用尾随,:
i = 1, # one element tuple
Run Code Online (Sandbox Code Playgroud)
如果您喜欢让人困惑,您可以随时使用以下list版本:
[*x] = p
Run Code Online (Sandbox Code Playgroud)
它做了完全相同的事情,但没有那个额外的逗号挂在那里.