为什么在 Python 3.8之前,使用没有括号的 return 语句进行带星号的迭代解包是无效的?

Python 语言(尤其是3.x)允许使用非常通用的 打开行李迭代器,一个简单的例子是

a, *rest = 1, 2, 3

多年来,这种解包已经逐渐被推广(参见 PEP 3132PEP 448) ,允许它在越来越多的情况下使用。因此,我很惊讶地发现在 Python 3.6中下面的语法是无效的(在 Python 3.7中仍然如此) :

def f():
rest = [2, 3]
return 1, *rest  # Invalid

我可以像这样把返回的元组封装在括号中:

def f():
rest = [2, 3]
return (1, *rest)  # Valid

我在 return语句中使用这一点似乎很重要,因为

t = 1, *rest

实际上是合法的,结果是有括号和没有括号的结果是一样的。

Python 开发人员是否已经忘记了这种情况,或者有什么理由说明这种情况的语法是无效的?

关我什么事

这打破了我认为自己与 Python 语言之间的一个重要契约:

def f():
rest = [2, 3]
t = 1, *rest
return t

通常,当我有这样的代码时,我认为 t是一个临时名称,我应该能够去掉它,只需用它的定义代替底线中的 t。但是在这种情况下,这会导致代码无效

def f():
rest = [2, 3]
return 1, *rest

当然,在返回值周围放置括号没有什么大不了的,但是通常只需要额外的括号来区分几种可能的结果(分组)。这里的情况并非如此,因为省略括号并不会产生其他不想要的行为,而是根本不会产生行为。

更新

由于 Python 3.8(参见 这份名单上的第7项) ,上面讨论的通用语法现在是有效的。

11331 次浏览

I suspect this is an accident, based on the comments from this commit for Python 3.2.

That commit enabled the assignment expression to take a testlist_star_expr production (what allows the unparenthesized unpacking), but left the return statement taking a testlist production. I suspect the commit just missed this (and possibly other locations, but I'm focusing on the return_stmt production for now).

I went ahead and modified the Python Grammar/Grammar file to allow this. All of the tests continue to pass, including those in the test_grammar.py file (but this doesn't seem terribly exhaustive).

If you're curious, this is the change I made. Feel free to clone or download my fork.

UPDATE: I've submitted a bpo issue and a pull request for the return (and yield) unpacking.