Pourquoi une virgule de fin a-t-elle un SyntaxError dans une liste d’arguments qui utilise la syntaxe * args?

Pourquoi ne pouvez-vous pas utiliser une virgule de fin avec *args en Python? En d’autres termes, cela fonctionne

 >>> f(1, 2, b=4,) 

Mais cela ne

 >>> f(*(1, 2), b=4,) File "", line 1 f(*(1, 2), b=4,) ^ SyntaxError: invalid syntax 

C’est le cas avec Python 2 et Python 3.

Regardons la spécification du langage :

 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 

Passons en revue les parties qui nous intéressent:

 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 

Donc, après des arguments à un appel de fonction, nous avons droit à un supplément. Cela ressemble donc à un bogue dans l’implémentation de cpython.

Quelque chose comme: f(1, *(2,3,4), ) devrait fonctionner selon cette grammaire, mais pas dans CPython.


Dans une réponse précédente, Eric était lié à la spécification grammaticale CPython , qui inclut l’implémentation CPython de la grammaire ci-dessus. Ici c’est ci-dessous:

 arglist: (argument ',')* ( argument [','] | '*' test (',' argument)* [',' '**' test] | '**' test ) 

Notez que cette grammaire n’est pas la même que celle proposée par la spécification de langage. Je considère cela comme un bogue d’implémentation.


Notez qu’il existe des problèmes supplémentaires avec l’implémentation de CPython. Cela devrait également être supporté: f(*(1,2,3), *(4,5,6))

Curieusement, la spécification n’autorise pas f(*(1,2,3), *(4,5,6), *(7,8,9))

En regardant cela de plus près, je pense que cette partie de la spécification doit être corrigée. Ceci est autorisé: f(x=1, *(2,3)) , mais ce n’est pas: f(x=1, 2, 3) .


Et pour être peut-être utile à la question initiale, dans CPython, vous pouvez avoir une virgule de fin si vous n’utilisez pas la fonctionnalité *args ou la fonctionnalité **kwargs . Je suis d’accord que c’est boiteux.

Après avoir discuté de ce bogue dans le numéro 9232 , Guido van Rossum a déclaré :

Je suis +1 en ajoutant ceci. Je ne crois pas que cela nécessite un PEP. Une virgule de fin dans les définitions est déjà prise en charge à certains endroits, donc je n’achète pas l’argument selon lequel il détecte des erreurs. Pendant le moratoire, nous étions peut-être trop ssortingcts.

Par la suite, un patch par Mark Dickinson a été commis. Donc, ceci est maintenant corrigé dans Python 3.6.0 alpha 1.