Python 理解*x,=lst
我正在浏览一些旧代码,试图理解它的功能,我遇到了一个奇怪的语句:Python 理解*x,=lst,python,python-3.x,iterable-unpacking,Python,Python 3.x,Iterable Unpacking,我正在浏览一些旧代码,试图理解它的功能,我遇到了一个奇怪的语句: *x ,= p dis('x = p') 1 0 LOAD_NAME 0 (p) 2 STORE_NAME 1 (x) p是此上下文中的一个列表。我一直在想这句话是怎么说的。据我所知,它只是将x的值设置为p。例如: p = [1,2] *x ,= p print(x) 只给 [1, 2] 这和x=p有什么不
*x ,= p
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
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()中引入的一个特性。在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)
及
自Python 3.3以来,list对象实际上有一个用于复制的方法:
x = p.copy()
切片实际上是一个非常相似的概念。然而,正如nneonneo所指出的,这只适用于支持切片的对象,如列表和元组。但是,您提到的方法适用于任何iterable:字典、集合、生成器等。您应该始终将这些元素扔给,看看它会给您带来什么;您将看到
*x,=p
实际上与x=p
有什么不同:
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
而简单赋值语句:
*x ,= p
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
(剥离不相关的None
returns)
正如您所看到的,解包是不同的操作码;:
使用星号目标实现赋值:将TOS(堆栈顶部)中的iterable解压为单个值,其中值的总数可以小于iterable中的项数:其中一个新值将是所有剩余项的列表
这就是为什么,正如Eugene所指出的,您会得到一个名为x
的新对象,而不是对已经存在的对象的引用(如x=p
)
*x,
看起来确实很奇怪(这里还有多余的逗号),但这里需要它。左侧必须是元组或列表,并且由于在Python中创建单个元素元组的特殊性,您需要使用尾部的,
:
i = 1, # one element tuple
如果您喜欢混淆他人,您可以始终使用此列表的版本:
[*x] = p
它的作用完全相同,但没有多余的逗号。您可以从下面的示例中清楚地理解它
L = [1, 2, 3, 4]
while L:
temp, *L = L
print(temp, L)
它所做的是,front变量每次都会获取第一项,剩余的列表将被提供给L
输出如下所示
1 [2, 3, 4]
2 [3, 4]
3 [4]
4 []
再看看下面的例子
x, *y, z = "python"
print(x,y,z)
在这种情况下,x、z都将从字符串中获取每个字母,这意味着第一个字母将分配给x,最后一个字母将分配给z,其余字符串将分配给变量y
p ['y', 't', 'h', 'o'] n
再举一个例子,
a, b, *c = [0,1,2,3]
print(a,b,c)
0 1 [2,3]
边界情况:如果星型变量没有剩余值,那么它将得到一个空列表。
例如:
a,b=[1]
print(a,b)
1 []
这是不同的,因为它不是分配别名,而是复制列表。请参阅,省略逗号会给出一条错误消息,这可能是一个有趣的参考:“SyntaxError:带星号的分配目标必须位于列表或元组中”。还值得注意的是,逗号实际上属于*x
,,因为带星号的赋值必须在列表或元组中。因此,编写该语句的更明确的方法是(*x,)=p
,需要注意的是,当p
是任意可数时,该方法有效;p#=>[1,2]
到上半部分和x[0]=3;p#=>[3,2]
到第二位,来说明为什么是和=
是不同的。注意,您的第二位代码,x=p[:]
要求p
是可切片的。这不包括发电机之类的东西。等等,3.0!?我认为它是更新的版本,3.5或3.6或其他版本。@user2357112:In,你会发现这个要点:pep3132已被接受
。此外,政治公众人物本身说Python版本是3.0。我很确定情况一定是这样的。@zondo在Python3中,复制的切片方法有一个问题,您可以将其包括在内,因为这个问题只适用于Python3。(虽然只有Python 3.3及以上版本有。)@River:啊,是的。我已经忘记了那件事。我保留了这个片段,因为它不仅适用于列表,而且仍然是一种常见的策略,但我添加了.copy
方法。