为什么在 Python 3.8 之前,在 return 语句中加星标的可迭代解包是不带括号的无效语法?

Why is starred iterable unpacking in a return statement invalid syntax without parentheses before Python 3.8?

Python 语言(尤其是 3.x)允许对迭代对象进行非常普遍的解包,一个简单的例子是

a, *rest = 1, 2, 3

多年来,这种解包已逐渐推广(参见 PEP 3132 and PEP 448),使其可以在越来越多的情况下使用。因此,我惊讶地发现以下是 Python 3.6 中的无效语法(并且在 Python 3.7 中仍然如此):

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

我可以通过将 returned 元组封装在括号中来使其工作,如下所示:

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

在return值两边加括号当然没什么大不了的,但通常额外加括号只是为了区分几种可能的结果(分组)。此处情况并非如此,因为省略括号不会产生其他一些不需要的行为,而是根本不会产生任何行为。

更新

从 Python 3.8 开始(参见 this list 上的第 7 项),上面讨论的通用语法现在有效。

根据 this commit 对 Python 3.2.

的评论,我怀疑这是一个意外

该提交使赋值表达式能够采用 testlist_star_expr 产生式(允许未加括号的解包),但使 return 语句采用 testlist 产生式。我怀疑提交只是错过了这个(可能还有其他位置,但我现在专注于 return_stmt 生产)。

我继续修改 Python Grammar/Grammar 文件以允许这样做。所有测试都继续通过,包括 test_grammar.py 文件中的测试(但这似乎并不十分详尽)。

如果你好奇,this is the change I made. Feel free to clone or download my fork

更新: 我已经提交了 bpo issue and a pull request 用于 return(和收益)解包。