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

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

我们来看看语言规范 :

 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语法规范 ,其中包括上述语法的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**kwargsfunction,则可以使用尾随逗号。 我同意这是跛脚。

在对9232号问题进行了一些讨论之后,Guido van Rossum 评论道 :

我在+1上添加这个。 我不相信这需要一个PEP。 定义中的尾随逗号在某些地方已经得到支持,所以我不会购买它捕捉错误的观点。 在暂停期间,我们可能太严格了。

随后, 由马克·迪金森(Mark Dickinson )做了一个补丁 。 所以现在已经在Python 3.6.0 alpha 1中修复了。