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

在Python 3.4中,我打字

[] = "" 

它工作正常,没有例外引发。 虽然[]当然不等于""

 [] = () 

也工作正常。

 "" = [] 

如预期的那样引发了一个例外,

 () = "" 

如预期的那样引发了一个例外。 发生什么了?

你没有比较平等。 你正在分配

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

 foo, bar = 1, 2 

将这两个值分别赋值给foobar 。 所有你需要的是右边的一个序列或者可迭代的 ,左边的名字列表或元组。

当你这样做时:

 [] = "" 

您为的名称列表分配了一个序列(空string仍是序列)。

这和本质上是一样的:

 [foo, bar, baz] = "abc" 

你最终得到foo = "a"bar = "b"baz = "c" ,但是用更less的字符。

但是,您不能将其分配给string,因此分配左侧的""从不起作用,并且始终是语法错误。

请参阅作业语句文档 :

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

将对象分配给目标列表( 可选地包含在圆括号或方括号中)recursion地定义如下。

强调我的

Python不会为空列表抛出语法错误实际上是一个错误! 正式logging的语法不允许有空的目标列表,对于空()你会得到一个错误。 见bug 23275 ; 它被认为是一个无害的bug:

起点是认识到这已经很长时间了,是无害的。

另请参阅为什么它是有效的分配给一个空的列表,而不是一个空的元组?

它遵循文档中的Assignment语句部分规则,

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

如果target list是以逗号分隔的目标列表: 对象必须是与目标列表中的目标相同数目的项目,并且项目从左到右分配给相应的目标。

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

所以,当你说

 [] = "" 

""是一个可迭代的(任何有效的pythonstring都是可迭代的),它被解压到列表的元素上。

例如,

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

既然你有一个空的string和一个空的列表,没有什么可以解压的。 所以,没有错误。

但是,试试这个

 >>> [] = "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"情况下,您试图在空的variables列表上解压string"1" 。 所以它抱怨“太多的值解包(预期0)”。

同样的方式,在[a] = ""情况下,你有一个空string,所以没有真正的解压缩,但你打开一个variables,这是不可能的。 这就是为什么它抱怨“需要超过0个值才能解包”。

除此之外,正如你注意到的那样,

 >>> [] = () 

也抛出没有错误,因为()是一个空的元组。

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

当它被解压到一个空的列表上时,没有任何东西需要解压。 所以没有错误。


但是,当你这样做

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

如错误消息所示,您正试图分配给string文字。 这是不可能的。 这就是为什么你得到错误。 这就像是在说

 >>> 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) 

在这里,由于string是空的, 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 。 然后从堆栈顶部逐个指定左侧expression式的variables。


顺便说一下,在Python中,这是如何在同一expression式中执行多个赋值的。 例如,

 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指令处理,而不是构造元组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