Python元组在return语句中解压缩

Python tuple unpacking in return statement

python语言(尤其是3.x)允许对iterables进行非常一般的解包,一个简单的例子是

1
a, *rest = 1, 2, 3

多年来,这种拆包逐渐得到推广(如PEP 3132和PEP 448),使其能够在越来越多的情况下使用。因此,我惊奇地发现以下是Python3.6中的无效语法(在Python3.7中仍然如此):

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

我可以通过将返回的元组封装在括号中使其正常工作,如下所示:

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

我在return声明中使用这个事实似乎很重要,因为

1
t = 1, *rest

实际上是合法的,结果是相同的,带括号和不带括号。

这种情况是被Python开发人员简单地忘记了,还是有什么原因导致这种情况是无效的语法?

为什么我在乎

这打破了我认为我与Python语言之间的一个重要契约。考虑以下(也是有效的)解决方案:

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

通常情况下,当我有这样的代码时,我认为t是一个临时名称,我应该能够将它的定义简单地替换为t。在这种情况下,这会导致无效的代码

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

当然,在返回值周围加上括号没有什么大不了的,但是通常只需要附加括号来区分几个可能的结果(分组)。这里不是这样,因为省略括号不会产生其他不需要的行为,而是根本没有行为。


我怀疑这是一个意外,基于这个为Python3.2提交的注释。

该提交使赋值表达式能够接受testlist_star_expr生产(允许未附加的解包),但使返回语句接受testlist生产。我怀疑这项承诺刚刚错过(可能还有其他地点,但我现在主要关注的是return_stmt的生产)。

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

如果你好奇的话,这就是我做的改变。请随意克隆或下载我的叉子。

更新:我已经提交了一个BPO问题和一个退货(和收益)解包请求。