逗号语法:语句中悬挂逗号背后的基本原理是 SyntaxError

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

在Python中,一个变量或字面量后跟一个逗号是一个-tuple:

1, # (1,)

...和一系列以逗号分隔的 variables/literals(无论它们后面是否有悬挂逗号)也是一个 tuple:

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

但是,在 callable/function 中,此语法的处理方式有所不同,因为逗号用于分隔参数:

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

第一行似乎完全忽略了悬挂的逗号。第二行创建一个 one-tuple(如预期的那样)。这也适用于用户定义的函数(不知道为什么不会):

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

还要考虑 assert 的以下行为(这是一个语句,而不是一个函数):

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 

因此我对悬挂逗号的处理解释如下:

我的问题:我对上述行为的解释是否正确? Python 解释器是否简单地忽略参数列表中的悬挂逗号?此行为是否因 Python 实施而异?最后:为什么在语句末尾(语法错误)和参数列表末尾(无语法错误)悬挂逗号的处理不一致?

编辑:阅读答案并进一步思考后,我的解释应修改如下:

然而,这仍然留下了一个问题,为什么在为语句提供参数时不忽略悬挂逗号,而在为函数提供参数时忽略它们。

在任何以逗号分隔的列表(函数调用、list/dictionary 文字等)中,始终 忽略尾随逗号。您的 assert 示例 不是 逗号分隔的列表。

一元组需要尾随逗号的唯一原因是无法区分一元组和括号表达式。

元组由逗号定义,除非上下文为逗号定义了不同的含义。在那种情况下,您需要使用括号来区分什么是元组逗号和不同的逗号。

assert 不是一个函数,它是一个语句,所以括号不是语法的一部分。逗号 ,因此您需要括号来消除元组与断言表达式和失败消息之间逗号的歧义,但您仍然需要那里的逗号来定义元组。

在定义元组和在调用表达式中使用 a 时,都会始终忽略多余的尾随逗号。但是您需要注意何时创建元组以及何时将逗号用于不同的表达式。要创建一个元组,您至少需要一个逗号,而在调用中您不需要该逗号,因为调用语法未由逗号运算符定义。

来自 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: ().)

来自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.

强调我的。

最后,来自Calls documentation

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