繁体   English   中英

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

[英]Why isn't assigning to an empty list (e.g. [] = "") an error?

在 python 3.4 中,我正在输入

[] = "" 

它工作正常,没有引发异常。 虽然当然[]不等于之后的""

[] = ()

也工作正常。

"" = []

虽然按预期引发异常,

() = ""

虽然按预期引发异常。 发生什么了?

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

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

foo, bar = 1, 2

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

当你这样做时:

[] = ""

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

它与做的事情本质上是一样的:

[foo, bar, baz] = "abc"

你最终得到foo = "a" , bar = "b"baz = "c" ,但字符更少。

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

请参阅赋值语句文档

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

将对象分配给目标列表,可选择括在圆括号或方括号中,递归定义如下。

强调我的

Python 不会为空列表抛出语法错误实际上是一个错误! 官方记录的语法不允许空的目标列表,对于空的()你确实会得到一个错误。 错误 23275 它被认为是一个无害的错误:

出发点是认识到这已经存在很长时间并且是无害的。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM