了解* 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, = px = 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只是表示xp另一个名称。 但是,在这种情况下,这是一个新的列表,恰好在其中具有相同的值。 (您可能对“最小惊讶”和可变默认参数感兴趣)

其他两种常见的产生这种效应的方式是:

 >>> 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 

它完全一样的东西,但没有额外的逗号挂在那里。