这些Python符号是什么:`[[]] * n`和`(i,)`

时间:2013-10-15 06:57:24

标签: python syntax

有人可以在Python中澄清这两个符号:

  • [ [] ] * n:显然这会创建对同一对象的n个引用(在本例中为空列表)。在哪种情况下这有用?
  • (i,):我看到有些人在sets函数的定义中使用了这种“尾随逗号”符号(例如:Generating all size k subsets of {0, 1, 2, ... n-1})。这是什么意思?

4 个答案:

答案 0 :(得分:10)

是的,确实会创建对同一对象的引用:

>>> L = [[]] * 3
>>> L
[[], [], []]
>>> L[0].append(1)
>>> L
[[1], [1], [1]]
>>> map(id, L)
[4299803320, 4299803320, 4299803320]

这对于您想要创建具有相同项目的对象非常有用。


(i,)使用项i创建一个元组:

>>> mytuple = (5,)
>>> print mytuple
(5,)
>>> print type(mytuple)
<type 'tuple'>

需要逗号的原因是因为否则它将被视为整数:

>>> mytuple = (5)
>>> print mytuple
5
>>> print type(mytuple)
<type 'int'>

答案 1 :(得分:3)

[ [] ] * n创建对同一个空列表对象的n个引用。这几乎总是一个错误,因为通常你最终会在其中一个n列表上使用破坏性操作,然后当它应用于外部列表中的“所有”元素时会感到惊讶。

但是[0] * n创建对同一整数零对象的n引用。像这样的表达式可以很方便地初始化计数器列表(你可能会继续替换列表中的各个插槽)。由于整数是不可变的,因此没有意外地改变“全部”零的危险。对于任何其他“不可变的一直向下”类型也是如此(不一定是元组,因为虽然元组本身是不可变的,但它可以包含可变值)。

所以这个“列表乘法”操作并没有用。但我建议避免使用之外的复制保证不可变值列表的具体情况。虽然可以安全地使用可变值列表可以,但它是如此脆弱,并且经常是错误的根本原因,即使这是你的意思,你最好在稍微冗长一点的方式让你明白你真正的意思。


对于(i,),Python允许在列表,字典,元组和集合文字中使用“额外”逗号。例如,以下各项均有效:

(1, 2, 3,)
[1, 2, 3,]
{1: 'one', 2: 'two', 3: 'three',}
{1, 2, 3,}

如果你遗漏了尾随的逗号,这没有任何不同之处,只是允许它作为可选的附加内容。

返回(i,)。这只是一个带有尾随逗号的项目的元组。但是有一个问题;对于仅包含一个项目的元组的特殊情况,尾随逗号不是可选的附加,它是强制。这是因为“one-tuple”否则会被写成(i),但是已经采用了这种句法形式来使用括号来对子表达式进行分组(例如,你无法判断(1 + 1) * 2是否是假设生成4(2, 2))。


顺便说一下,当您将多元组/列表/字典/集分割为多行时,您可能希望使用可选尾随逗号的原因有时更明显:

foo = [
   'this',
   'is',
   'a',
   'long',
   'list',
]

使用此样式编写,只需重新排序源代码行即可重新排序列表。如果我重新订购的项目之一是列表中的最后一项,我就不必去清理逗号。

同样,如果我正在使用版本控制,则在最后一个项目之后添加更多项目不会更改先前最终项目的行,因此差异是纯粹的添加。如果最后一行没有逗号,则需要添加一个以添加更多项目,这会将更改记录为对该行的编辑,这会使合并冲突(稍微)更可能,并且历史记录(稍微)更难以读取。

答案 2 :(得分:0)

[[]] * n创建对同一可变列表的引用。很多时候,这不是所需要的,而是需要可以单独修改的唯一列表对象。要做到这一点,你可以使用它:

list_of_lists = [[] for x in xrange(n)]

答案 3 :(得分:0)

到目前为止,[...] * n的最常见用途必须是grouper recipe

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)