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

我知道一个列表理解会做到这一点,但我想知道是否有更短(更Pythonic?)的方法。

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

[e for number in xrange(n)] 

为每个列表?

你也可以写:

 [e] * n 

你应该注意,如果e是例如一个空列表,你会得到一个列表,其中n个引用同一个列表,而不是n个独立的空列表。

性能testing

乍一看,重复是用n个相同元素创build列表的最快方式:

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

但是等等 – 这不是一个公平的testing…

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

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

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

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

 >>> [5] * 4 [5, 5, 5, 5] 

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

 >>> x=[5] >>> y=[x] * 4 >>> y [[5], [5], [5], [5]] >>> y[0][0] = 6 >>> y [[6], [6], [6], [6]] 

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

不变的物品

对于不可变的项目,如无,string,元组或frozensets,你可以这样做:

 [e] * 4 

请注意,这最好只用于列表中不可变的项目(string,元组,frozensets),因为它们都指向内存中同一位置的相同项目。 当我必须用一个所有string的模式构build一个表格时,我经常使用它,所以我不必一一给出一个映射。

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

可变的项目

我已经使用Python很长一段时间了,我从来没有见过一个用例,我会做一个可变的实例上述。 相反,要得到一个可变的空列表,设置或字典,你应该这样做:

 list_of_lists = [[] for _ in columns] 

在这种情况下,下划线只是一个一次性的variables名称。

如果你只有号码,那将是:

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

_并不是特别的,但是如果你不打算使用variables并使用其他名字,你的编码环境风格检查器可能会抱怨。


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

要小心这个可变对象 ,当你改变它们之一时,它们都会改变,因为它们都是同一个对象:

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

foo现在返回:

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

但是对于不可变的对象,你可以使它工作,因为你改变了引用而不是对象:

 >>> 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([])] 

但是,可变对象又是不好的,因为就地操作会改变对象而不是引用:

 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只是为了这个function:

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

当然itertools给你一个迭代器而不是一个列表。 [e] * n给你一个列表,但是,根据你将要用这些序列做什么, itertools变种可以更有效率。

正如其他人指出的那样,使用*运算符作为可变对象会复制引用,所以如果更改引用,则可以将其全部更改。 如果你想创build一个可变对象的独立实例,那么你的xrange语法就是最好的Pythonic方法。 如果您有一个永远不会使用的命名variables,您可以使用匿名下划线variables。

 [e for _ in xrange(n)] 
 [e] * n 

应该工作