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功能,则可以使用尾随逗号.我同意这是蹩脚的.
在对9232问题中的这个错误进行了一些讨论后,Guido van Rossum 评论道:
我添加这个+1.我认为它不需要PEP.某些地方已经支持定义中的尾随逗号,因此我不会购买它捕获错误的论点.在暂停期间,我们可能过于严格.
随后,Mark Dickinson发布了一个补丁.所以这现在在Python 3.6.0 alpha 1中得到修复.