在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 
应该工作