在Python中创建单项重复n次的列表

Create List of Single Item Repeated n Times in Python

我知道单子上的理解可以做到这一点,但我想知道是否还有一个更短(更多的Python?)接近。

我想创建一系列长度不同的列表。每个列表将包含相同的元素e,重复n次(其中n=列表的长度)。如何创建列表,而不做

1
[e for number in xrange(n)]

对于每个列表?


你也可以写:

1
[e] * n

您应该注意,如果e是一个空列表,那么您会得到一个对同一个列表有n个引用的列表,而不是n个独立的空列表。

性能测试

乍一看,repeat似乎是创建具有n个相同元素的列表的最快方法:

1
2
3
4
>>> timeit.timeit('itertools.repeat(0, 10)', 'import itertools', number = 1000000)
0.37095273281943264
>>> timeit.timeit('[0] * 10', 'import itertools', number = 1000000)
0.5577236771712819

但是等等-这不是一个公平的测试…

1
2
>>> itertools.repeat(0, 10)
repeat(0, 10)  # Not a list!!!

函数itertools.repeat实际上并不创建列表,它只是创建一个对象,如果您愿意,可以使用该对象创建列表!让我们再试一次,但转换为列表:

1
2
>>> timeit.timeit('list(itertools.repeat(0, 10))', 'import itertools', number = 1000000)
1.7508119747063233

所以如果你想要一个列表,使用[e] * n。如果您希望惰性地生成元素,请使用repeat


1
2
>>> [5] * 4
[5, 5, 5, 5]

当要重复的项目是列表时要小心。不会克隆列表:所有元素都将引用同一列表!

1
2
3
4
5
6
7
>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]


Create List of Single Item Repeated n Times in Python

号不可变项

对于不可变项(如无、字符串、元组或冻结集),可以这样做:

1
[e] * 4

请注意,这最好只用于列表中不可变的项(字符串、元组、冻结集),因为它们都指向内存中相同位置的相同项。当我必须用所有字符串的模式构建一个表时,我经常使用这个方法,这样就不必给出一对一的映射。

1
schema = ['string'] * len(columns)

可变项目

我已经使用Python很长一段时间了,我从来没有看到过一个用例,在这个用例中,我将使用一个可变的实例来完成上面的工作。相反,要得到一个可变的空列表、集合或dict,您应该这样做:

1
list_of_lists = [[] for _ in columns]

在这个上下文中,下划线只是一个一次性变量名。

如果你只有这个号码,那就是:

1
list_of_lists = [[] for _ in range(4)]

_并不是特别的,但是如果您不打算使用变量和任何其他名称,那么您的编码环境样式检查程序可能会抱怨。

不可变项使用不可变方法的注意事项:

小心使用可变对象,当您更改其中一个对象时,它们都会更改,因为它们都是相同的对象:

1
2
foo = [[]] *4
foo[0].append('x')

foo现在返回:

1
[['x'], ['x'], ['x'], ['x']]

但对于不可变对象,您可以使其工作,因为您更改了引用,而不是对象:

1
2
3
4
5
6
7
8
9
>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]

>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]

但同样,可变对象不适合这样做,因为就地操作更改了对象,而不是引用:

1
2
3
4
l = [set()] * 4
>>> l[0] |= set('abc')    
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]


itertools的功能就是:

1
2
import itertools
it = itertools.repeat(e,n)

当然,itertools会给您一个迭代器,而不是一个列表。[e] * n为您提供了一个列表,但是,根据您将如何处理这些序列,itertools变体可以更有效。


正如其他人所指出的,对可变对象使用*运算符会重复引用,因此,如果更改一个对象,则会全部更改。如果您想创建可变对象的独立实例,xrange语法是实现这一点的最简单的方法。如果您被一个从未使用过的命名变量所困扰,您可以使用匿名下划线变量。

1
[e for _ in xrange(n)]


1
[e] * n

应该工作