为什么在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都是这种情况。

最佳答案

让我们看看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功能,则可以使用逗号结尾。我同意这很la脚。

09-10 11:26
查看更多