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


72

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

>>> 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都是这种情况。


4
与这种方式有关(1,)的可能会创建一个元组。
TankorSmash 2013年

3
显然关键字args不相关。f(*args,)也不允许。
asmeurer 2013年

11
@ user2246674“为什么”远非无关紧要-正是问题的关键所在。像Python这样的语言语法是精心打造的,用了很多考虑投资于可读性,易用性,易解析,向后兼容性等方面很可能落后的原因是逗号到处允许一个原因,除了*args,它是对这个原因感到好奇是合法的。如果您不同意,那么还有许多其他问题需要回答。
user4815162342 2013年

1
@ user4815162342:我不同意。我认为规范可以在这里使用一些工作。f(x=1, *(2, 3))允许,但f(x=1, 2, 3)不允许。f(1, 2, x=3,)允许,但f(*(1, 2), x=3,)不允许。
Bill Lynch 2013年

2
@sharth由于您自己的回答表明该实现与规范不符,因此不妨说应该修复该实现。无论哪种方式,这都与提出问题的合法性正交。这个问题的答案还可能是它是一个简单的疏忽(如我的第一条评论中所述)或一个实现错误— Python语法可能是精心设计的,但没有人是完美的。
user4815162342 2013年

Answers:


102

让我们看一下语言规范

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

因此,看起来像在调用函数的任何参数之后,都允许有一个extra ,。因此,这看起来像是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**kwargs功能,可以使用逗号结尾。我同意这很la脚。


16
得到支持。这是我第一次看到有人提出Python语言规范来支持答案。
lightalchemist 2013年

总的来说,好的答案。但是我不确定当您说f(*(1,2,3), *(4,5,6))“应该被支持”时您是什么意思-在我看来,语法(语言规范和cpython语法)都不允许这样做。
爱德华·罗伯

2
@EdwardLoper可能指的是规范语法的这一行| "*" expression ["," "*" expression] ["," "**" expression]。方括号中的第一个子句似乎错误地到达了该行,该行应为| "*" expression ["," "**" expression]。正如sharth所说,规范确实需要一些工作。
user4815162342

6
此问题已于2010
Aliaksei Ramanau

2
@dr .:感谢您在跟踪器中找到有关此内容的信息。我没有机会四处看看。看来您已引用的错误应作为此错误的副本而关闭:bugs.python.org/issue9232,它们标记为已取代10682。–
Bill Lynch

6

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

我对此加+1。我认为这不需要PEP。某些地方已经支持在定义中使用逗号结尾,因此我不赞成它捕获错误的说法。在暂停期间,我们也许太严格了。

随后,马克·迪金森(Mark Dickinson)提交了补丁。因此,这已在Python 3.6.0 alpha 1中修复。


1
棒极了!我最初在实际代码中遇到了这个问题,花了一些时间才弄清楚为什么Python告诉我我有语法错误。
asmeurer 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.