理解*x,= lst

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)

  • 另外值得注意的是,逗号实际上属于`*x`,因为已加星标的赋值必须在列表或元组中.所以编写该语句的更明确的方式是`(*x,)= p` (13认同)
  • 重要的是要注意,当`p`是*any*iterable时,这是有效的. (2认同)

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指出的那样,它仅适用于支持切片的列表和元组等对象.但是,您提到的方法适用于任何可迭代的:字典,集合,生成器等.

  • @ user2357112:在[Python 3.0中的新功能](https://www.python.org/download/releases/3.0/whatsnew/)中,你会发现这个要点:'PEP 3132被接受了'.此外,PEP本身表示Python版本为3.0.我很确定那一定是这样的. (2认同)

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)

它做了完全相同的事情,但没有那个额外的逗号挂在那里.