赋值语句左侧和右侧的星号 * 运算符

Star * operator on left vs right side of an assignment statement

据我所知,这个问题源于 PEP 448 -- Additional Unpacking Generalizations 并且出现在 Python 3.5 中(并且没有反向移植到 2.x)。具体来说,在 缺点 部分中,注意以下内容:

Whilst *elements, = iterable causes elements to be a list, elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.

这确实成立,对于 iterable = [1, 2, 3, 4],第一种情况产生 list:

>>> *elements, = iterable
>>> elements
[1, 2, 3, 4]

而对于第二种情况,创建了 tuple

>>> elements = *iterable,
>>> elements
(1, 2, 3, 4)

概念不熟,一头雾水。谁能解释这种行为?加星号的表情是否会根据它所在的一侧而有所不同?

在考虑扩展解包的初始 PEP 时解释了这两种情况之间的区别:PEP 3132 -- Extended iterable unpacking

在该 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 始终是包含 iterable 中所有项目的 list

尽管这两种情况看起来很相似,但本例(左侧)中的 * 意味着:捕获所有未分配给名称的内容并将其分配给加星标的表达式。它的工作方式与 *args**kwargs 函数定义 .

中的工作方式类似
def spam(*args, **kwargs): 
    """ args and kwargs group positional and keywords respectively """

第二种情况(右侧)有些不同。这里我们没有 * 以 "catch everything" 的方式工作,就像我们通常在 函数调用 中那样工作。它扩展了它所附加的可迭代对象的内容。所以,语句:

elements = *iterable, 

可以看作:

elements = 1, 2, 3, 4, 

这是 tuple 的另一种初始化方式。

请注意,可以通过简单地使用 elements = [*iterable] 创建 list,这将在 [] 中解压 iterable 的内容,并生成以下形式的赋值elements = [1, 2, 3, 4]