了解* x,= lst
我正在浏览一些旧代码,试图理解它的作用,并且我遇到了这个奇怪的声明:
*x ,= p
p
是这个上下文中的一个列表。 我一直在试图弄清楚这个陈述的作用。 据我所知,它只是将x
设置为p
的值。 例如:
p = [1,2]
*x ,= p
print(x)
只是给了
[1, 2]
那么这与x = p
什么不同呢? 任何想法这个语法在做什么?
*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
这是一个在Python 3.0中引入的功能(PEP 3132)。 在Python 2中,你可以这样做:
>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3
Python 3对此进行了扩展,以便一个变量可以保存多个值:
>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]
因此,这是在这里使用的。 然而,不是两个变量需要保存三个值,而只是一个变量,它取得列表中的每个值。 这与x = p
不同,因为x = p
只是表示x
是p
另一个名称。 然而,在这种情况下,这是一个刚好在其中具有相同值的新列表。 (您可能对“最小惊讶”和可变默认参数感兴趣)
产生这种效应的另外两种常见方式是:
>>> x = list(p)
和
>>> x = p[:]
自Python 3.3以来,列表对象实际上有一个用于复制的方法:
x = p.copy()
切片实际上是一个非常相似的概念。 然而,nneonneo指出,这只适用于支持切片的列表和元组等对象。 但是,您提到的方法适用于任何迭代:字典,集合,生成器等。
你应该总是把这些给dis
,看看它在你身上背; 你会看到*x, = p
实际上与x = p
是不同的:
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
虽然,简单的任务说明:
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
(剥离不相关的None
回报)
正如你所看到的, UNPACK_EX
是它们之间的不同操作码; 它记录为:
实现具有星标目标的赋值:将TOS(堆栈顶部)中的iterable解包为单个值,其中值的总数可以小于迭代中的项的数量:其中一个新值将成为all剩余物品。
正如Eugene指出的那样,这就是为什么你得到一个名称为x
的新对象,而不是对已经存在的对象的引用(就像x = p
的情况一样)。
*x,
看起来很奇怪(这里和所有额外的逗号),但它在这里是必需的。 左手边必须是一个元组或列表,并且由于在Python中创建一个单一的元素元组的诡诈,你需要使用一个尾随,
:
i = 1, # one element tuple
如果你喜欢迷惑人,你可以使用这个list
版本:
[*x] = p
它完全一样的东西,但没有额外的逗号挂在那里。
链接地址: http://www.djcxy.com/p/18801.html