[] =(),()=()和{} =()'赋值'

Chr*_*nds 37 python python-2.7 python-3.x

我惊讶地发现以下内容,在Python 3中,前两个没有提出任何结果:

>>> [] = ()
>>> () = ()
>>> {} = ()
  File "<stdin>", line 1
SyntaxError: can't assign to literal
Run Code Online (Sandbox Code Playgroud)

在Python 2.7中,只有第一个没有提出任何东西:

>>> [] = ()
>>> () = ()
  File "<stdin>", line 1
SyntaxError: can't assign to ()
>>> {} = ()
  File "<stdin>", line 1
SyntaxError: can't assign to literal
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?那么为什么没有提出任何错误呢?为什么() = ()可能在Python 3中被添加为有效?

*注意,您可以用任何空的可迭代(例如[] = set())替换右侧,我只选择一个空的元组用于插图

Chr*_*nds 28

根据Issue23275,这些基本上是怪癖,没有造成真正的伤害,但也没有效用.请注意,[] = ()不会改变list文字:

>>> [] = ()
>>> type([])
<class 'list'>
Run Code Online (Sandbox Code Playgroud)

[] = x语句基本断言x是可迭代的并且x是空的(尽管没有人会建议以这种方式使用它们),例如

>>> [] = (1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> [] = (1,)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
Run Code Online (Sandbox Code Playgroud)

正如John Y所评论的那样,最好将其[] = ()视为一种赋值,而不是与Python的可迭代解包语法一致的方式.

正如ArrowCase所述,此语法还扩展到多个赋值:

>>> a = [] = ()
>>> a
()
Run Code Online (Sandbox Code Playgroud)

查看多重赋值的CPython字节码说明此操作类似于普通的可迭代解包语法,使用以下UNPACK_SEQUENCE指令:

>>> dis.dis('a = [] = ()')
  1           0 BUILD_TUPLE              0
              2 DUP_TOP
              4 STORE_NAME               0 (a)
              6 UNPACK_SEQUENCE          0
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
>>> dis.dis('[a, b] = (1, 2)')
  1           0 LOAD_CONST               3 ((1, 2))
              2 UNPACK_SEQUENCE          2
              4 STORE_NAME               0 (a)
              6 STORE_NAME               1 (b)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

相同的Issue23275声明() = ()作为有效语法添加到Python 3的一致性.决定删除[] = ()会不必要地破坏代码,因为它不会造成任何伤害并且适合可迭代的解包逻辑.{} = ()仍然无效,因为在带有大括号的上下文中,解包语法没有意义.

如果有人想知道,语法就像list() = ()语法上的无效,因为你永远不能分配给函数调用.

  • @StefanPochmann - 您实际上不能*分配给元组或列表.但那些是序列,因此你可以*解包*(顺序分配)到它们的**元素**.字典不是一个序列,它本身没有"元素",它有键值对. (6认同)
  • @Munir不,不一样.你可以做`{} [0] =(1,2)`而不是`[] =(1,2)`. (2认同)

glg*_*lgl 26

有一种方法可以从iterable中分配变量:

>>> a, b = iter((1, 2))
>>> a
1
>>> b
2
>>> [c, d] = iter((4, 5))
>>> c
4
>>> d
5
Run Code Online (Sandbox Code Playgroud)

这些[] = …() = …作业似乎是这些的特殊情况.

  • 你实际上不必说`iter(...)`.你可以简单地做'a,b = 1,2' (6认同)
  • 最好将有关案件称为堕落而非特殊.它们源于一致的行为应用. (6认同)
  • @DeepSpace glglgl无法知道这一点.看起来对我有意,有点"匿名化"元组,强调它可以是任何可迭代的. (4认同)

Rei*_*ica 9

赋值语句的左侧不是表达式,而是目标列表.简短的摘要:

  • 如果目标列表是标识符,则名称仅绑定到右侧.
  • 如果目标列表是逗号分隔的目标列表,则右侧将被解压缩,并且解压缩的元素将分配给列出的目标.
  • 目标列表可以括在括号或方括号中.特别是,这允许创建空目标列表,如示例中所示.

这解释了为什么[]并且()是作业的有效左侧:它们是有效的目标列表.但是,{}不是,因为它不是有效的目标列表.

当然,{}可能是目标的一部分,例如作为订阅的主要部分:{}[()] = 0是有效的python(当然,但完全没用).


use*_*ica 7

这是将两元素迭代解包为两个赋值目标的语法:

[x, y] = whatever
Run Code Online (Sandbox Code Playgroud)

这可以概括最多三个或更多目标,但它也可以概括为:

[x] = whatever
Run Code Online (Sandbox Code Playgroud)

将一个元素的iterable解包为一个赋值目标,并且

[] = whatever
Run Code Online (Sandbox Code Playgroud)

将零元素迭代解包为零分配目标(如果whatever是零元素可迭代则不执行任何操作,如果不是则抛出异常).

() = whatever也解包零元素可迭代,但{} = whatever没有; 没有涉及大括号的解压缩赋值语法.