在元组定义中,有尾随逗号的语法规则是什么?

158
在单个元素的元组中,需要使用尾随逗号。
a = ('foo',)

那么对于拥有多个元素的元组呢?似乎无论是否存在尾随逗号,它们都是有效的。这样说对吗?在我看来,使用尾随逗号更容易进行编辑。那样是否是一种不好的编码风格?

a = ('foo1', 'foo2')
b = ('foo1', 'foo2',)

1
这是语法规则:http://docs.python.org/reference/expressions.html#expression-lists - Kirill
10个回答

132

只有在定义单个元素的元组时需要使用括号来消除一个表达式与一个元组之间的歧义。

(1)  # the number 1 (the parentheses are wrapping the expression `1`)
(1,) # a 1-tuple holding a number 1

对于不止一个元素的情况,这个逗号已经不再必需了,因为很清楚它是一个元组。但是,末尾的逗号可以让使用多行定义它们变得更加容易。你可以在末尾添加或重新排列元素,而不会因为不小心漏掉逗号而破坏语法。

例如:

someBigTuple = (
                   0,
                   1,
                   2,
                   3,
                   4,
                   5,
                   6,
                   7,
                   8,
                   9,
                   10,
                   #...
                   10000000000,
               )

请注意,这也适用于其他集合(例如列表和字典),而不仅仅是元组。


7
感谢你指出这也适用于除了元组之外的其他东西。这对于每行只有一个 key: value, 时非常有用,无需在添加新内容时再考虑逗号的问题。 - Joël

78

对于除了空元组以外的所有情况,逗号都是重要的。只有在必要的语法情况下,才需要使用括号:用于区分元组和函数参数集、操作符优先级,或者允许换行。

对于元组、列表或函数参数来说,末尾加逗号是良好的风格,特别是当你有一个长的初始化被拆分成多个行时。如果你总是包含一个尾随逗号,那么你不会添加另一行到期望添加另一个元素的末尾,并且只是创建一个有效的表达式:

a = [
   "a",
   "b"
   "c"
]

假设开始是一个由两个元素组成的列表,而后被扩展,这种方式可能不会立即引起问题。始终包含尾随逗号可以避免这种错误。


4
出于以上原因,留下逗号会更有优势。但另一方面,如果你在应用程序的其他位置也涉及 JavaScript 或 JSON,采用这种习惯可能会导致头疼,因为某些浏览器不支持它。 - Cito
7
是的,但是你不应该手工构建JSON,所以这并不重要,对于JavaScript,请始终使用jslint或等效工具在它接近浏览器之前捕捉此类错误。 - Duncan

57

尾逗号的另一个优点是让差异看起来更好看。如果你从下面这样开始:

a = [
    1,
    2,
    3
]

并将其更改为

a = [
    1,
    2,
    3,
    4
]

差异将如下所示

 a = [
     1,
     2,
-    3
+    3,
+    4
 ]

如果您一开始就在最后添加了逗号,就像这样:

a = [
    1,
    2,
    3,
]

那么,差异只是

 a = [
     1,
     2,
     3,
+    4,
 ]

1
这其实更像是对原问题的评论而非答案,但我真的很喜欢为尾随逗号辩护的附加论点。 - Mad Physicist

16

这是可选的:查看Python维基

总结:只有一个元素的元组需要一个尾逗号,但对于多个元素的元组来说,则是可选的


8

此外,考虑以下情况:

您需要:
>>> (('x','y'))*4                         # same as ('x','y')*4
('x', 'y', 'x', 'y', 'x', 'y', 'x', 'y')
#Expected = (('x', 'y'), ('x', 'y'), ('x', 'y'), ('x', 'y'))

所以在这种情况下,外层括号仅仅是分组括号。如果要将它们变成元组,需要加上一个逗号,例如:
>>> (('x','y'),)*4 
(('x', 'y'), ('x', 'y'), ('x', 'y'), ('x', 'y'))

不要认为这个答案与问题无关,而是滥用了元组。如果我们期望重复的元素是元组类型,我们需要显式地将此单元的类型声明为单元素元组。与列表相同,尝试使用['x', 'y'] * 4[ ['x', 'y'] ] * 4( ['x', 'y'], ) * 4 - Kuo

7

这是一个简单的答案。

a = ("s") 是一个字符串

a = ("s",) 是一个只包含一个元素的元组。

在Python中,当元组只有一个元素时,需要添加额外的逗号以区分字符串和元组。

例如,在Python控制台上尝试执行以下操作:

a = ("s")

a  = a + (1,2,3)

Traceback (most recent call last):

File stdin, line 1, in module

TypeError: cannot concatenate 'str' and 'tuple' objects

1
这与问题有什么关系?!楼主问的是当元组有多个元素时,他是否需要在最后加逗号:t = (1, 2,)t = (1, 2) - zardosht

6

只有一个元素的元组需要使用尾逗号。对于较大的元组,尾逗号是一种风格,不是必需的。它最大的优点是在具有多行大元组的文件上进行干净的差异比较,这些文件经常被修改(例如配置元组)。


4

PEP 8 -- Python代码风格指南 - 何时使用尾随逗号

尾随逗号通常是可选的,除非在创建一个元素的元组时是必需的(在Python 2中它们对于print语句有意义)。为了清晰起见,建议将后者括在(技术上多余的)括号中。

是:

FILES = ('setup.cfg',)

好的,但有些混乱:

FILES = 'setup.cfg',

当尾逗号是多余的时候,它们通常在使用版本控制系统时非常有用,当预计随时间推移扩展值、参数或导入项列表时。模式是将每个值(等)单独放在一行上,始终添加一个尾随逗号,并在下一行上添加关闭括号/括号/大括号。然而,在与结束分隔符相同的行上使用尾随逗号是没有意义的(除了单例元组的情况)。
是的:
FILES = [
    'setup.cfg',
    'tox.ini',
    ]
initialize(FILES,
           error=True,
           )

编号:

FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)

4

这里存在的另一个原因是它使代码生成和__repr__函数更易编写。例如,如果您有一些像obj(arg1, arg2, ..., argn)这样构建的对象,则只需编写obj.__repr__即可:

def __repr__(self):
    l = ['obj(']
    for arg in obj.args: # Suppose obj.args == (arg1, arg2, ..., argn)
        l.append(repr(arg))
        l.append(', ')
    l.append(')')
    return ''.join(l)

如果不允许使用尾随逗号,您将不得不特殊处理最后一个参数。实际上,您可以使用列表推导式在一行中编写上述内容(我已经将其写得更长,以使其更易于阅读)。如果您不得不特殊处理最后一个术语,这样做就不那么容易了。

2
不需要特别处理最后一个参数,可以在这种情况下使用 joindef __repr__(self): 'obj(' + ', '.join([repr(arg) for arg in obj.args]) + ')' - Suzanne Soy
它还有助于代码生成,即使是从不使用Python编写且没有像join这样的好函数的工具。 - asmeurer

-7

编程风格是你的品味,如果你认为编码规范很重要,那么有一个PEP-8可以指导你。

你认为遵循这个表达式的结果如何?

x = (3)
x = (3+2)
x = 2*(3+2)

没错,x只是一个数字。


3
那种方式解释你的思路是不好的。明确比含蓄更好。 - Guilherme David da Costa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接