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

4

请问有人能澄清Python中的这两个符号:

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

3
(i,)жҳҜдёҖдёӘеҢ…еҗ«е…ғзҙ iзҡ„е…ғз»„гҖӮжң«е°ҫзҡ„йҖ—еҸ·жҳҜеӣ дёә(i)зӯүеҗҢдәҺiгҖӮ - falsetru
1
请注意,在 i, 中不需要括号。 - Lie Ryan
1
@LieRyan,这取决于所使用的表达式/语句。return i,a, = [1]等是可以的。但对于func(i,)i, + another_tuple等则不行。 - falsetru
  1. [[]]*n,它会在列表中添加 n 次 '[]'。因此,如果我们考虑 n=3,则会产生结果 [[], [], []]。
  2. (i,) 是一个元组,尾随逗号用于区分元组和普通括号操作。
- Nilesh
4个回答

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'>

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,)这个问题。这只是一个带有尾逗号的一项元组。但有一个陷阱;对于仅包含一个项目的元组的特殊情况,尾逗号不是可选的额外内容,而是强制性的。这是因为“单元素元组”否则将被写为(i),但该语法形式已经用于使用括号来分组子表达式(例如,否则你无法确定(1 + 1)* 2是应该产生4还是(2,2))。
另外,你可能想有时使用可选的尾逗号的原因更明显,当你将长元组/列表/字典/集合分成多行时:
foo = [
   'this',
   'is',
   'a',
   'long',
   'list',
]

使用这种风格的书写方式使我能够通过重新排列源代码行来重新排序列表; 如果我重新排序的其中一项是列表中的最后一项,我就不必去清理逗号。

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


1

[[]] * n会创建对同一个可变列表的引用。很多时候这不是需要的,相反你需要独立修改的唯一列表对象。为了做到这一点,你可以使用以下代码:

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


0

到目前为止,[...] * n 最常见的用途必须是 分组配方

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)

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