Why can't you use a trailing comma with *args
in Python? In other words, this works
>>> f(1, 2, b=4,)
But this does not
>>> f(*(1, 2), b=4,)
File "<stdin>", line 1
f(*(1, 2), b=4,)
^
SyntaxError: invalid syntax
This is the case with both Python 2 and Python 3.
It helps to eliminate a certain kind of bug. It's sometimes clearer to write lists on multiple lines. But in, later maintenace you may want to rearrange the items. But if you allow trailing commas, and use them, you can easily rearrange the lines without introducing an error.
A trailing comma, also known as a dangling or terminal comma, is a comma symbol that is typed after the last item of a list of elements. Since the introduction of the JavaScript language, trailing commas have been legal in array literals. Later, object literals joined arrays.
JavaScript has allowed trailing commas in array literals since the beginning, and later added them to object literals, and more recently, to function parameters and to named imports and named exports. JSON, however, disallows trailing commas.
1. "trailingComma": "es5" says that the trailing comma is invalid after the last property.
Let's look at the 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
Let's sift down to the parts we care about:
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
So, it looks like after any arguments to a function call, we're allowed an extra ,
. So this looks like a bug in the cpython implementation.
Something like: f(1, *(2,3,4), )
should work according to this grammar, but doesn't in CPython.
In an earlier answer, Eric linked to the CPython grammar specification, which includes the CPython implementation of the above grammar. Here it is below:
arglist: (argument ',')* ( argument [',']
| '*' test (',' argument)* [',' '**' test]
| '**' test
)
Note, that this grammar is not the same as the one proposed by the language specification. I'd consider this an implementation bug.
Note that there are additional issues with the CPython implementation. This should also be supported: f(*(1,2,3), *(4,5,6))
Oddly though, the specification does not allow f(*(1,2,3), *(4,5,6), *(7,8,9))
As I look at this more, I think this part of the specification needs some fixing. This is allowed: f(x=1, *(2,3))
, but this isn't: f(x=1, 2, 3)
.
And to perhaps be helpful to the original question, in CPython, you can have a trailing comma if you don't use the *args
or the **kwargs
feature. I agree that this is lame.
After some discussion regarding this bug in issue 9232, Guido van Rossum commented:
I'm +1 on adding this. I don't believe it requires a PEP. A trailing comma in definitions is already supported in some places, so I don't buy the argument that it catches errors. During the moratorium we were perhaps too strict.
Subsequently, a patch by Mark Dickinson was committed. So this is now fixed in Python 3.6.0 alpha 1.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With