为什么在参数列表中使用* args语法的尾随逗号是SyntaxError?

时间:2013-06-05 21:42:19

标签: python syntax python-internals

为什么你不能在Python中使用带*args的尾随逗号?换句话说,这是有效的

>>> f(1, 2, b=4,)

但这不是

>>> f(*(1, 2), b=4,)
  File "<stdin>", line 1
    f(*(1, 2), b=4,)
                   ^
SyntaxError: invalid syntax

Python 2和Python 3就属于这种情况。

2 个答案:

答案 0 :(得分:100)

让我们看一下language specification

call                 ::=  primary "(" [argument_list [","]
                          | expression genexpr_for] ")"
argument_list        ::=  positional_arguments ["," keyword_arguments]
                            ["," "*" expression] ["," keyword_arguments]
                            ["," "**" expression]
                          | keyword_arguments ["," "*" expression]
                            ["," "**" expression]
                          | "*" expression ["," "*" expression] ["," "**" expression]
                          | "**" expression
positional_arguments ::=  expression ("," expression)*
keyword_arguments    ::=  keyword_item ("," keyword_item)*
keyword_item         ::=  identifier "=" expression

让我们来看看我们关心的部分:

call                 ::=  primary "(" [argument_list [","]] ")"
argument_list        ::=  positional_arguments ["," keyword_arguments]
                            ["," "*" expression] ["," keyword_arguments]
                            ["," "**" expression]
positional_arguments ::=  expression ("," expression)*
keyword_arguments    ::=  keyword_item ("," keyword_item)*
keyword_item         ::=  identifier "=" expression

因此,看起来在函数调用的任何参数之后,我们允许额外的,。所以这看起来像是cpython实现中的一个错误。

类似于:f(1, *(2,3,4), )应该根据这个语法工作,但不在CPython中。


在之前的回答中,Eric链接到CPython grammar specification,其中包括上述语法的CPython实现。它在下面:

arglist: (argument ',')* ( argument [',']
                         | '*' test (',' argument)* [',' '**' test] 
                         | '**' test
                         )

请注意,此语法与语言规范提出的不一样。我认为这是一个实现错误。


请注意,CPython实现还存在其他问题。这也应得到支持:f(*(1,2,3), *(4,5,6))

奇怪的是,规范不允许f(*(1,2,3), *(4,5,6), *(7,8,9))

在我看到这个时,我认为规范的这一部分需要一些修复。允许这样做:f(x=1, *(2,3)),但这不是:f(x=1, 2, 3)


或许对原始问题有帮助,在CPython中,如果您不使用*args**kwargs功能,则可以使用尾随逗号。我同意这是蹩脚的。

答案 1 :(得分:6)

issue 9232中对此错误进行了一些讨论后,Guido van Rossum commented

  

我在添加此内容时+1。我不相信它需要一个PEP。某些地方已经支持定义中的尾随逗号,因此我不会购买它捕获错误的论点。在暂停期间,我们可能过于严格。

随后,a patch by Mark Dickinson被提交。所以现在修复了Python 3.6.0 alpha 1。