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

asm*_*rer 69 python syntax python-internals

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

>>> f(1, 2, b=4,)
Run Code Online (Sandbox Code Playgroud)

但事实并非如此

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

Python 2和Python 3都是这种情况.

Bil*_*nch 100

我们来看看语言规范:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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


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

arglist: (argument ',')* ( argument [',']
                         | '*' test (',' argument)* [',' '**' test] 
                         | '**' test
                         )
Run Code Online (Sandbox Code Playgroud)

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


请注意,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功能,则可以使用尾随逗号.我同意这是蹩脚的.

  • 得到了这个.这是我第一次看到有人拿出Python的语言规范来支持答案. (16认同)
  • 此问题已于2010-12-12提交到python bug跟踪器并被拒绝:http://bugs.python.org/issue10682 (6认同)
  • @EdwardLoper可能指的是`|的规范语法行 "*"表达式[",""*"表达式] [",""**"表达式]`.方括号中的第一个子句看起来像是错误地到达那里,该行应该是`| "*"表达式[",""**"表达式]`.正如Sharth所说,规范确实需要一些工作. (2认同)
  • @dr.:感谢您在跟踪器中找到关于此的内容.我没有机会环顾四周.看起来你引用的错误应该被关闭为这个错误:http://bugs.python.org/issue9232,它们标记为取代了10682. (2认同)

Bio*_*eek 6

在对9232问题中的这个错误进行了一些讨论后,Guido van Rossum 评论道:

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

随后,Mark Dickinson发布了一个补丁.所以这现在在Python 3.6.0 alpha 1中得到修复.