Skip to content
Advertisement

Comma Syntax: rationale behind a hanging comma in a statement being a SyntaxError

In Python, a variable or literal followed by a hanging comma is a one-tuple:

1, # (1,)

…and a series of comma-separated variables/literals (whether or not they are followed by a hanging comma) is also a tuple:

1,2, # (1,2)
1,2 # (1,2)

However, inside a callable/function, this syntax is treated differently, because the comma is used for separation of arguments:

bool(5>6,) # False - 5>6 == False
bool((5>6,)) # True - (5>6,) is a non-empty tuple (always True - contents ignored)

The first line seems to simply ignore the hanging comma. The second line creates a one-tuple (as expected). This holds true for user-defined functions as well (don’t know why it wouldn’t):

def f(arg):
    pass
f(1,) # No Error 

Consider also the following behavior of assert (which is a statement, not a function):

assert 5>6 # AssertionError, as expected 
assert(5>6) # AssertionError, as expected 
assert 5>6, # SyntaxError: invalid syntax
assert(5>6,) # SyntaxWarning: assertion always true, perhaps remove parentheses?
assert 5>6, 'NOPE!' # AssertionError: NOPE!, as expected 

Therefore my interpretation of the treatment of hanging commas is as follows:

  • If the comma is in the context of function arguments, it is ignored
  • If the comma is in the context of a statement, it is a syntax error
  • Elsewhere, it is interpreted as part of a tuple object

My question: is my interpretation of the above behavior correct? Does the Python interpreter simply ignore hanging commas found in argument lists? Does this behavior vary by Python implementation? Finally: WHY is there an inconsistency in the treatment of a hanging comma at the end of a statement (syntax error) and at the end of an argument list (no syntax error)?

EDIT: After reading the answers and thinking it through a bit more, my interpretation should be amended as follows:

  • The hanging comma is ALWAYS IGNORED, except in the following two contexts
  • If the hanging comma is in the context of a statement, it is a syntax error
  • If the hanging comma signals a one-tuple

However, this still leaves the question of WHY the hanging comma is not ignored for supplying arguments to statements, when they are ignored for supplying arguments to functions.

Advertisement

Answer

A tuple is defined by the comma, unless the context has defined a different meaning for the comma. In that case you need to use parentheses to disambiguate what is a tuple comma and a different comma.

assert is not a function, it is a statement, so paretheses are not part of the syntax. Commas are, so you need the parentheses to disambiguate the tuple from the comma between the assertion expression and the failure message, but you still need the comma there to define the tuple.

Both when defining a tuple and using a in a call expression, a surplus trailing comma is ignored, consistently. But you need to be aware of when you are creating a tuple and when you are using the comma for a different expression. To create a tuple, you need at least one comma, while in a call you don’t need to have that comma because the call syntax is not defined by the comma operator.

From the documentation on Expression lists:

An expression list containing at least one comma yields a tuple. The length of the tuple is the number of expressions in the list. The expressions are evaluated from left to right.

The trailing comma is required only to create a single tuple (a.k.a. a singleton); it is optional in all other cases. A single expression without a trailing comma doesn’t create a tuple, but rather yields the value of that expression. (To create an empty tuple, use an empty pair of parentheses: ().)

and from Parethesized forms:

A parenthesized form is an optional expression list enclosed in parentheses:

parenth_form ::=  "(" [expression_list] ")"

A parenthesized expression list yields whatever that expression list yields: if the list contains at least one comma, it yields a tuple; otherwise, it yields the single expression that makes up the expression list.

An empty pair of parentheses yields an empty tuple object. Since tuples are immutable, the rules for literals apply (i.e., two occurrences of the empty tuple may or may not yield the same object).

Note that tuples are not formed by the parentheses, but rather by use of the comma operator. The exception is the empty tuple, for which parentheses are required — allowing unparenthesized “nothing” in expressions would cause ambiguities and allow common typos to pass uncaught.

Emphasis mine.

Finally, from the Calls documentation:

A trailing comma may be present after the positional and keyword arguments but does not affect the semantics.

4 People found this is helpful
Advertisement