代码之家  ›  专栏  ›  技术社区  ›  jmd_dk

为什么在Python 3.8之前,带星号的iterable解包在返回语句中没有括号的语法无效?

  •  85
  • jmd_dk  · 技术社区  · 7 年前

    Python语言(尤其是3.x)允许非常通用的 拆包 一个简单的例子是

    a, *rest = 1, 2, 3
    

    多年来,这种拆包已逐渐普及(例如。 PEP 3132 PEP 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语言签订的一项重要合同。考虑以下(也是有效的)解决方案:

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

    通常,当我有这样的代码时,我会考虑 t 作为一个临时的名字,我应该能够摆脱它,只要替换一下 t 在其定义的底线。但在这种情况下,这会导致无效代码

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

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

    使现代化

    自Python 3.8以来(请参见 this list ),上面讨论的通用语法现在有效。

    1 回复  |  直到 3 年前
        1
  •  41
  •   David Cuthbert    7 年前

    我怀疑这是一起事故,根据 this commit 对于Python 3.2。

    该提交使赋值表达式能够采用 testlist_star_expr 生产(什么允许无标题的解包),但将返回语句保留为 testlist 生产我怀疑提交只是错过了这个(可能还有其他位置,但我关注的是 return_stmt 目前的生产)。

    我继续修改了Python语法/语法文件以允许这样做。所有测试继续通过,包括 test_grammar.py 文件(但这似乎不是非常详尽)。

    如果你好奇, this is the change I made . 请随意克隆或下载 my fork .

    更新: 我已经提交了一份 bpo issue 和a pull request 用于退货(和退换货)开箱。