为什么不分配给空列表(例如[] =“”)错误?


110

在python 3.4中,我输入

[] = "" 

并且工作正常,不会引发异常。虽然当然[]不等于""事后。

[] = ()

也可以。

"" = []

引发异常,

() = ""

引发异常,但是如预期的那样。发生什么了?

Answers:


132

您不是为了平等而比较。您正在分配

Python允许您分配给多个目标:

foo, bar = 1, 2

将两个值分别分配给foobar。您所需要的只是右侧的序列可迭代,左侧的是名称列表或元组。

当您这样做时:

[] = ""

您分配了一个名称列表序列(空字符串仍然是序列)。

本质上与执行此操作相同:

[foo, bar, baz] = "abc"

在哪里结束foo = "a"bar = "b"以及baz = "c",但字符数减少了。

但是,您无法分配给字符串,因此 ""在的左侧永远不会起作用,并且始终是语法错误。

请参阅赋值语句文档

赋值语句评估表达式列表(请记住,它可以是单个表达式或逗号分隔的列表,后者产生一个元组),并将单个结果对象从左到右分配给每个目标列表。

将对象分配给目标列表(可选地用括号或方括号括起来)的方式如下所述。

强调我的

Python不会为空列表引发语法错误实际上是一个错误!正式记录的语法不允许有空的目标列表,并且对于空的目标,()确实会出错。见bug 23275 ; 它被认为是无害的错误:

起点是认识到这种情况已经存在很长时间并且是无害的。

另请参见为什么分配给空列表而不分配给空元组有效吗?


36

它遵循文档中“ 分配声明”部分的规则,

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)

如果target list是用逗号分隔的目标列表:该对象必须是可迭代的,并且具有与目标列表中的目标相同数量的项,并且这些项从左到右分配给相应的目标。

该对象必须是与目标列表中的目标具有相同数量项的序列,并且这些项从左到右分配给相应的目标。

所以,当你说

[] = ""

"" 是可迭代的(任何有效的python字符串都是可迭代的),并且正在列表的元素上解压缩。

例如,

>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')

由于您有一个空字符串和一个空列表,因此无需解压缩。因此,没有错误。

但是,尝试一下

>>> [] = "1"
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack

在这种[] = "1"情况下,您尝试将字符串解压缩到"1"一个空变量列表中。因此,它抱怨“解压缩的值太多(预期为0)”。

同样,[a] = ""以防万一,您有一个空字符串,因此实际上没有要解压缩的内容,但是您正在通过一个变量解压缩它,这也是不可能的。这就是为什么它抱怨“需要超过0个值才能解包”。

除此之外,您已经注意到,

>>> [] = ()

也不会引发错误,因为()是一个空的元组。

>>> ()
()
>>> type(())
<class 'tuple'>

当将其解压缩到一个空列表中时,没有任何要解压缩的内容。所以没有错误。


但是,当你这样做

>>> "" = []
  File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
  File "<input>", line 1
SyntaxError: can't assign to literal

如错误消息所述,您正在尝试分配给字符串文字。这是不可能的。这就是为什么您会得到错误。就像在说

>>> 1 = "one"
  File "<input>", line 1
SyntaxError: can't assign to literal

内部构造

在内部,此分配操作将转换为UNPACK_SEQUENCE操作码,

>>> dis(compile('[] = ""', "string", "exec"))
  1           0 LOAD_CONST               0 ('')
              3 UNPACK_SEQUENCE          0
              6 LOAD_CONST               1 (None)

在这里,由于字符串为空,因此将UNPACK_SEQUENCE解压缩0时间。但是当你有这样的事情

>>> dis(compile('[a, b, c] = "123"', "string", "exec"))
  1           0 LOAD_CONST               0 ('123')
              3 UNPACK_SEQUENCE          3
              6 STORE_NAME               0 (a)
              9 STORE_NAME               1 (b)
             12 STORE_NAME               2 (c)
             15 LOAD_CONST               1 (None)
             18 RETURN_VALUE

该序列123从右到左解压到堆栈中。因此,堆栈的顶部为,1下一个为2,最后一个为3。然后,它从堆栈的顶部开始逐一分配左侧表达式中的变量。


顺便说一句,在Python中,这就是您可以在同一表达式中进行多个分配的方式。例如,

a, b, c, d, e, f = u, v, w, x, y, z

之所以可行,是因为使用右手边的值构造一个元组,然后将其拆开到左手边的值上。

>>> dis(compile('a, b, c, d, e, f = u, v, w, x, y, z', "string", "exec"))
  1           0 LOAD_NAME                0 (u)
              3 LOAD_NAME                1 (v)
              6 LOAD_NAME                2 (w)
              9 LOAD_NAME                3 (x)
             12 LOAD_NAME                4 (y)
             15 LOAD_NAME                5 (z)
             18 BUILD_TUPLE              6
             21 UNPACK_SEQUENCE          6
             24 STORE_NAME               6 (a)
             27 STORE_NAME               7 (b)
             30 STORE_NAME               8 (c)
             33 STORE_NAME               9 (d)
             36 STORE_NAME              10 (e)
             39 STORE_NAME              11 (f)
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE

但是经典的交换技术a, b = b, a使用堆栈顶部的元素旋转。如果只有两个或三个元素,则将使用特殊的ROT_TWOROT_THREE说明来对待它们,而不是构造元组和拆包。

>>> dis(compile('a, b = b, a', "string", "exec"))
  1           0 LOAD_NAME                0 (b)
              3 LOAD_NAME                1 (a)
              6 ROT_TWO
              7 STORE_NAME               1 (a)
             10 STORE_NAME               0 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE

您也可以dis('[] = ""')不致电使用compile()
Andrea Corbellini,2015年

您能否使用上一个示例中的方法描述如果交换三个以上变量/元素时会发生什么情况?
nanofarad

@hexafraction它将在右侧创建所有元组的新元组,然后在左侧的变量上解压缩它们。
thefourtheye 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.