在python 3.4中,我正在输入
[] = ""
并且它工作正常,不会引发异常。虽然之后[]
当然不等于""
。
[] = ()
也可以。
"" = []
按预期引发异常,
() = ""
尽管如此提出了一个异常。那么,发生了什么?
答案 0 :(得分:132)
你不是在比较平等。您分配。
Python允许您分配多个目标:
foo, bar = 1, 2
分别将这两个值分配给foo
和bar
。您所需要的只是右侧的序列或可迭代,以及左侧的名称列表或元组。
当你这样做时:
[] = ""
您将一个空序列(空字符串仍为序列)分配给一个空的名称列表。
这与做的基本相同:
[foo, bar, baz] = "abc"
您最终得到foo = "a"
,bar = "b"
和baz = "c"
,但字符数较少。
但是,您不能分配给字符串,因此分配左侧的""
永远不会起作用,并且始终是语法错误。
请参阅Assignment statements documentation:
赋值语句计算表达式列表(请记住,这可以是单个表达式或以逗号分隔的列表,后者产生元组)并将单个结果对象从左到右分配给每个目标列表。
和
将对象分配给目标列表,可选地括在括号或方括号中,递归定义如下。
强调我的。
Python没有为空列表抛出语法错误实际上是一个bug!官方记录的语法不允许空目标列表,而对于空()
,您确实会收到错误。见bug 23275;它被认为是一个无害的错误:
出发点是认识到它已存在很长时间并且无害。
另见Why is it valid to assign to an empty list but not to an empty tuple?
答案 1 :(得分:36)
遵循文档中的Assignment statements section规则,
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"
解压缩到一个空的变量列表中。所以它抱怨&#34;太多的值要解包(预期为0)&#34;。
同样地,在[a] = ""
的情况下,你有一个空字符串,所以没有什么可以真正解压缩,但是你正在将它解压缩到一个变量上,这也是不可能的。这就是为什么它抱怨&#34;需要超过0的值才能解包&#34;。
除此之外,正如您所注意到的,
>>> [] = ()
也不会抛出任何错误,因为()
是一个空元组。
>>> ()
()
>>> 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
。然后它从堆栈顶部逐个指定左侧表达式中的变量。
BTW,在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_TWO
和ROT_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