了解* 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
不同,因为前者创buildp
的副本 (即新列表),而后者创build对原始列表的引用 。 为了显示:
>>> 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 )中引入的function。 在Python 2中,你可以这样做:
>>> p = [1, 2, 3] >>> q, r, s = p >>> q 1 >>> r 2 >>> s 3
Python 3对此进行了扩展,以便一个variables可以保存多个值:
>>> p = [1, 2, 3] >>> q, *r = p >>> q 1 >>> r [2, 3]
因此,这是在这里使用的。 然而,并不是两个variables需要保存三个值,而只是一个variables来获取列表中的每个值。 这与x = p
不同,因为x = p
只是表示x
是p
另一个名称。 但是,在这种情况下,这是一个新的列表,恰好在其中具有相同的值。 (您可能对“最小惊讶”和可变默认参数感兴趣)
其他两种常见的产生这种效应的方式是:
>>> x = list(p)
和
>>> x = p[:]
自Python 3.3以来,列表对象实际上有一个旨在复制的方法:
x = p.copy()
切片实际上是一个非常相似的概念。 正如nneonneo指出的,但是,这只适用于支持切片的列表和元组等对象。 你提到的方法,但是,与任何可迭代的工作:字典,集,发电机等。
你总是应该抛弃这些东西,看看它给你带来什么; 你会看到*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
是它们之间的不同的操作码。 它被logging为 :
实现具有星标目标的赋值:将TOS(堆栈顶部)中的iterable解包为单个值,其中值的总数可以小于迭代中的项数:其中一个新值将是所有剩余物品。
正如Eugene指出的那样,这就是为什么你得到一个新的对象,这个对象被称为x
而不是对已经存在的对象的引用(就像x = p
的情况一样)。
*x,
看起来很奇怪(多余的逗号),但在这里是必需的。 左侧必须是元组或列表,并且由于在Python中创build单个元素元组的奇怪之处,您需要使用尾部的:
i = 1, # one element tuple
如果你喜欢混淆的人,你总是可以使用这个list
版本:
[*x] = p
它完全一样的东西,但没有额外的逗号挂在那里。