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

Posted

技术标签:

【中文标题】赋值语句左侧和右侧的星 * 运算符【英文标题】:Star * operator on left vs right side of an assignment statement 【发布时间】:2016-06-08 18:53:31 【问题描述】:

这个问题源于PEP 448 -- Additional Unpacking Generalizations,据我所知,它存在于 Python 3.5 中(而不是向后移植到2.x)。具体而言,在缺点部分中,指出了以下内容:

虽然*elements, = iterable 导致elements 成为listelements = *iterable,导致elements 成为tuple。其原因可能会使不熟悉该构造的人感到困惑。

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

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

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

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

不熟悉这个概念,我很困惑。谁能解释这种行为?加星号的表情是否会根据其所在的一侧而有所不同?

【问题讨论】:

【参考方案1】:

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

在该 PEP 的摘要中,我们可以看到:

此 PEP 提议对可迭代解包语法进行更改,允许指定一个“包罗万象”的名称,将分配一个列表,其中包含未分配给“常规”名称。

(强调我的)

所以在第一种情况,执行后:

*elements, = iterable

elements 始终是一个list,包含iterable 中的所有项目。

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

def spam(*args, **kwargs): 
    """ args and kwargs group positional and keywords respectively """

第二种情况(右侧)有些不同。在这里,* 不像我们在 函数调用 中通常那样以“捕获一切”的方式工作。它扩展了它所附加的可迭代对象的内容。所以,声明:

elements = *iterable, 

可以看成:

elements = 1, 2, 3, 4, 

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

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

【讨论】:

以上是关于赋值语句左侧和右侧的星 * 运算符的主要内容,如果未能解决你的问题,请参考以下文章

PHP 3 运算符 if...else...elseif 语句

RTL基本知识:阻塞赋值与非阻塞赋值

Verilog 的连续赋值

了解 Python 多重赋值

Python赋值运算符(入门必读)

C语言中赋值语句的语法是怎样的