赋值语句左侧和右侧的星号*运算符
此问题源自 PEP 448
-其他拆包概述和据我所知,它在Python 3.5中存在(并且没有反向移植到2.x
).具体来说,在缺点部分中,注意以下几点:
This questions stems from PEP 448
-- Additional Unpacking Generalizations and is present in Python 3.5 as far as I'm aware (and not back-ported to 2.x
). Specifically, in the section Disadvantages, the following is noted:
*elements, = iterable
使elements
成为list
时,elements = *iterable
,导致elements
是tuple
.原因可能会使不熟悉该结构的人感到困惑.
Whilst
*elements, = iterable
causeselements
to be alist
,elements = *iterable
, causeselements
to be atuple
. The reason for this may confuse people unfamiliar with the construct.
对于iterable = [1, 2, 3, 4]
确实成立,第一种情况产生list
:
Which does indeed hold, for iterable = [1, 2, 3, 4]
, the first case yields a list
:
>>> *elements, = iterable
>>> elements
[1, 2, 3, 4]
在第二种情况下,创建了tuple
:
While for the second case a tuple
is created:
>>> elements = *iterable,
>>> elements
(1, 2, 3, 4)
不熟悉这个概念,我很困惑.谁能解释这种行为?加星标的表情是否会因其所在的侧面而有所不同?
Being unfamiliar with the concept, I am confused. Can anyone explain this behavior? Does the starred expression act differently depending on the side it is on?
在还考虑了扩展包装的初始PEP时,解释了这两种情况之间的区别:
The difference between these two cases are explained when also taking into consideration the initial PEP for extended unpacking: PEP 3132 -- Extended iterable unpacking
.
在该PEP的摘要中,我们可以看到:
In the Abstract for that PEP we can see that:
此PEP建议更改可迭代的拆包语法,允许指定一个包罗万象"的名称, 将被分配一个列表, 常规"名称.
This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.
(重点是我的)
因此,在第一种情况下,在执行后:
*elements, = iterable
elements
始终是一个list
,其中包含iterable
中的所有项目.
elements
is always going to be a list
containing all the items in the iterable
.
即使在两种情况下看起来都相似,在这种情况下(左侧)的*
表示:捕获未分配给名称的所有内容并将其分配给加星号的表达式.它的作用方式与函数定义中的*args
和**kwargs
相似.
Even though it seems similar in both cases, the *
in this case (left-side) means: catch everything that isn't assigned to a name and assign it to the starred expression. It works in a similar fashion as *args
and **kwargs
do in function definitions.
def spam(*args, **kwargs):
""" args and kwargs group positional and keywords respectively """
第二种情况(右侧)有些不同.在这里,我们没有像函数调用中那样使*
以捕获所有内容"的方式像通常那样工作.它扩展了附加到其上的可迭代对象的内容.因此,声明:
The second case (right-side) is somewhat different. Here we don't have the *
working in a "catch everything" way as much as we have it working as it usually does in function calls. It expands the contents of the iterable it is attached to. So, the statement:
elements = *iterable,
可以被视为:
elements = 1, 2, 3, 4,
这是tuple
初始化的另一种方式.
which is another way for a tuple
to be initialized.
请注意,可以简单地使用elements = [*iterable]
创建list
,这将解压缩[]
中iterable
的内容并产生elements = [1, 2, 3, 4]
形式的赋值.
Do note, a list
can be created by simple using elements = [*iterable]
which will unpack the contents of iterable
in []
and result in an assignments of the form elements = [1, 2, 3, 4]
.