简体   繁体   English

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

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

In python 3.4, I am typing在 python 3.4 中,我正在输入

[] = "" 

and it works fine, no Exception is raised.它工作正常,没有引发异常。 Though of course [] is not equal to "" afterwards.虽然当然[]不等于之后的""

[] = ()

also works fine.也工作正常。

"" = []

raises an exception as expected though,虽然按预期引发异常,

() = ""

raises an exception as expected though.虽然按预期引发异常。 So, what's going on?发生什么了?

You are not comparing for equality.你不是为了平等而比较。 You are assigning .您正在分配.

Python allows you to assign to multiple targets: Python 允许您分配给多个目标:

foo, bar = 1, 2

assigns the two values to foo and bar , respectively.将这两个值分别分配给foobar All you need is a sequence or iterable on the right-hand side, and a list or tuple of names on the left.您所需要的只是右侧的序列可迭代对象,以及左侧的名称列表或元组。

When you do:当你这样做时:

[] = ""

you assigned an empty sequence (empty strings are sequences still) to an empty list of names.您为的名称列表分配了一个序列(空字符串仍然是序列)。

It is essentially the same thing as doing:它与做的事情本质上是一样的:

[foo, bar, baz] = "abc"

where you end up with foo = "a" , bar = "b" and baz = "c" , but with fewer characters.你最终得到foo = "a" , bar = "b"baz = "c" ,但字符更少。

You cannot, however, assign to a string, so "" on the left-hand side of an assignment never works and is always a syntax error.但是,您不能分配给字符串,因此分配左侧的""永远不起作用,并且始终是语法错误。

See the Assignment statements documentation :请参阅赋值语句文档

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.赋值语句评估表达式列表(请记住,这可以是单个表达式或逗号分隔的列表,后者产生一个元组)并将单个结果对象从左到右分配给每个目标列表。

and

Assignment of an object to a target list, optionally enclosed in parentheses or square brackets , is recursively defined as follows.将对象分配给目标列表,可选择括在圆括号或方括号中,递归定义如下。

Emphasis mine .强调我的

That Python doesn't throw a syntax error for the empty list is actually a bit of a bug! Python 不会为空列表抛出语法错误实际上是一个错误! The officially documented grammar doesn't allow for an empty target list, and for the empty () you do get an error.官方记录的语法不允许空的目标列表,对于空的()你确实会得到一个错误。 See bug 23275 ;错误 23275 it is considered a harmless bug:它被认为是一个无害的错误:

The starting point is recognizing that this has been around for very long time and is harmless.出发点是认识到这已经存在很长时间并且是无害的。

Also see Why is it valid to assign to an empty list but not to an empty tuple?另请参阅为什么分配给空列表有效而不分配给空元组?

It follows the Assignment statements section rules from the documentation,它遵循文档中的赋值语句部分规则,

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

If the target list is a comma-separated list of targets: The object must be an iterable with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.如果target list是一个逗号分隔的目标列表:对象必须是一个可迭代对象,其项目数与目标列表中的目标数量相同,并且项目从左到右分配给相应的目标。

The object must be a sequence with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.对象必须是一个序列,其项目数与目标列表中的目标数量相同,并且项目从左到右分配给相应的目标。

So, when you say所以,当你说

[] = ""

"" is an iterable (any valid python string is an iterable) and it is being unpacked over the elements of the list. ""是一个可迭代的(任何有效的 python 字符串都是一个可迭代的),并且它正在被解包到列表的元素上。

For example,例如,

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

Since you have an empty string, and an empty list, there is nothing to unpack.由于您有一个空字符串和一个空列表,因此无需解包。 So, no error.所以,没有错误。

But, try this但是,试试这个

>>> [] = "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

In the [] = "1" case, you are trying to unpack the string "1" over an empty list of variables.[] = "1"情况下,您试图将字符串"1"解压到一个空的变量列表上。 So it complains with "too many values to unpack (expected 0)".所以它抱怨“解包的值太多(预期为 0)”。

Same way, in [a] = "" case, you have an empty string, so nothing to unpack really, but you are unpacking it over one variable, which is, again, not possible.同样,在[a] = ""情况下,您有一个空字符串,因此实际上没有什么可解压的,但是您将它解压到一个变量上,这又是不可能的。 That is why it complains "need more than 0 values to unpack".这就是为什么它抱怨“需要超过 0 个值才能解包”。

Apart from that, as you noticed,除此之外,正如你所注意到的,

>>> [] = ()

also throws no error, because () is an empty tuple.也不会抛出错误,因为()是一个空元组。

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

and when it is unpacked over an empty list, there is nothing to unpack.当它在一个空列表上解包时,没有什么可以解包的。 So no error.所以没有错误。


But, when you do但是,当你这样做

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

as the error message says, you are trying to assign to a string literal.正如错误消息所说,您正在尝试分配给字符串文字。 Which is not possible.这是不可能的。 That is why you are getting the errors.这就是为什么你会收到错误。 It is like saying就像在说

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

Internals内件

Internally, this assignment operation will be translated to UNPACK_SEQUENCE op code,在内部,这个赋值操作会被翻译成UNPACK_SEQUENCE操作码,

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

Here, since the string is empty, UNPACK_SEQUENCE unpacks 0 times.这里,由于字符串为空, UNPACK_SEQUENCE解包0次。 But when you have something like this但是当你有这样的事情

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

the sequence 123 is unpacked in to the stack, from right to left.序列123从右到左解压到堆栈中。 So, the top of the stack would be 1 and the next would be 2 and the last would be 3 .因此,堆栈的顶部将是1 ,下一个将是2 ,最后一个将是3 Then it assigns from the top of the stack to the variables from the left hand side expression one by one.然后它从栈顶开始将左侧表达式中的变量一一赋值。


BTW, in Python, this is how you can do multiple assignments in the same expression.顺便说一句,在 Python 中,这就是您可以在同一个表达式中进行多个赋值的方式。 For example,例如,

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

this works because, the right hand values are used to construct a tuple and then it will be unpacked over the left hand side values.这是有效的,因为右侧的值用于构造一个元组,然后它将在左侧的值上解包。

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

but the classic swapping technique a, b = b, a uses rotation of elements in the top of the stack.但是经典的交换技术a, b = b, a使用堆栈顶部元素的旋转。 If you have only two or three elements then they are treated with specialROT_TWO and ROT_THREE instructions instead of constructing the tuple and unpacking.如果你只有两个或三个元素,那么它们会被特殊的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.

相关问题 关于 python 列表中错误的快速提问 * 常量,例如 [a, b, c, d, e ] * x - Quick question on error in python list * a constant e.g. [a , b, c, d , e ] * x 为什么空列表的大小不是 0 字节? - Why isn't the size of an empty list 0 bytes? 为什么当我尝试定义带注释的类型 class 成员(例如列表或字典)时 PyPy 失败? - Why PyPy fails when I try to define type annotated class member (e.g. list or dict)? 为什么Python 3找不到安装的软件包(例如BeautifulSoup4)? - Why doesn't Python 3 find installed packages (e.g. BeautifulSoup4)? 在 PySimpleGUI 中创建 window 布局时出现错误“您的行不是可迭代的(例如列表)” - Error "Your row is not an iterable (e.g. a list)" when creating window layout in PySimpleGUI Django 迁移错误:错误:“选择”必须是可迭代的(例如,列表或元组) - Django Migration Error: ERRORS: 'choices' must be an iterable (e.g., a list or tuple) 为什么 ctrl+c 必须是导致错误的组合(例如 KeyboardInterrupt)? - Why does ctrl+c have to be the combination to cause an error (e.g. KeyboardInterrupt)? Pycharm没有显示`PyQt5`程序的错误信息(例如`TypeError`) - Pycharm doesn't show error information for `PyQt5` program (e.g. `TypeError`) 使用NLTK查找事物列表(例如河流列表) - Find a list of things (e.g. a list of rivers) using NLTK 为什么不以不正确的方式为字典赋值是错误的? - Why isn't assigning a value to a dictionary in an incorrect way an error?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM