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

Posted

技术标签:

【中文标题】逗号语法:语句中悬挂逗号背后的基本原理是 SyntaxError【英文标题】:Comma Syntax: rationale behind a hanging comma in a statement being a SyntaxError 【发布时间】:2015-05-13 17:50:30 【问题描述】:

在 Python 中,后跟逗号的变量或文字是 one-tuple

1, # (1,)

...以及一系列以逗号分隔的变量/文字(无论是否后跟逗号)也是tuple

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

但是,在可调用/函数内部,此语法的处理方式有所不同,因为逗号用于分隔参数:

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

第一行似乎只是忽略了悬挂的逗号。第二行创建一个-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 

因此我对挂逗号的处理方式解读如下:

如果逗号在函数参数的上下文中,则会被忽略 如果逗号在语句的上下文中,则为语法错误 在其他地方,它被解释为tuple 对象的一部分

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

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

始终忽略悬挂逗号,但以下两种情况除外 如果悬挂逗号在语句的上下文中,则为语法错误 如果悬挂的逗号表示一个-tuple

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

【问题讨论】:

assert 不是一个函数,因此只有逻辑忽略括号除非你创建一个元组 【参考方案1】:

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

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

【讨论】:

“您的 assert 示例不是逗号分隔的列表” - 好吧,请参阅最后一个 assert 示例 assert 5>6, 'NOPE!' # AssertionError: NOPE!。我知道函数和语句是不同的,但这似乎仍然代表了提供给每个函数的逗号分隔参数的处理方式略有不一致。【参考方案2】:

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

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

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

来自Expression lists上的文档:

包含至少一个逗号的表达式列表产生一个元组。元组的长度是列表中表达式的数量。表达式从左到右计算。

尾随逗号仅用于创建单个元组(a.k.a. singleton);在所有其他情况下它是可选的。 没有尾随逗号的单个表达式不会创建元组,而是产生该表达式的值。 (要创建一个空元组,请使用一对空括号:()。)

来自Parethesized forms

括号形式是括号中的可选表达式列表:

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

带括号的表达式列表产生该表达式列表产生的任何内容:如果列表包含至少一个逗号,则产生一个元组;否则,它会产生构成表达式列表的单个表达式。

一对空括号产生一个空元组对象。由于元组是不可变的,因此适用于文字的规则(即,空元组的两次出现可能会或可能不会产生相同的对象)。

请注意,元组不是由括号构成,而是由逗号运算符构成。空元组是个例外,它需要括号——在表达式中允许不带括号的“无”会导致歧义,并允许常见的拼写错误通过而未被捕获。

强调我的。

最后,来自Calls documentation:

位置参数和关键字参数之后可能会出现尾随逗号,但不会影响语义。

【讨论】:

assert 之后的逗号没有其他含义” - 请参阅最后一个 assert 示例,assert 5>6, 'NOPE!' # AssertionError: NOPE!。我知道函数和语句是不同的,但这似乎仍然代表了提供给每个函数的逗号分隔参数的处理方式略有不一致。 @Rick:啊,是的;现在这样的逗号越来越少,但这就是其中之一。

以上是关于逗号语法:语句中悬挂逗号背后的基本原理是 SyntaxError的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 数据字段值是用逗号隔开,如何写SQL语句

mysql from 逗号 是join的简写吗

如何在打印语句中的变量旁边添加逗号和句点

java用if语句要怎么判断一个字符串里是不是有逗号?

js中的逗号运算符

javascript(ECMAScript)中逗号运算符的基本使用方法