我需要初始化一个默认值列表。如果他们是字符串,这将是整洁的:
list_of_dds = [string] * n
...但是对于可变数据,你会遇到这种方法:
>>> x=[defaultdict(list)] * 3
>>> x[0]['foo'] = 'bar'
>>> x
[defaultdict(<type 'list'>, {'foo': 'bar'}), defaultdict(<type 'list'>, {'foo': 'bar'}), defaultdict(<type 'list'>, {'foo': 'bar'})]
我所做的想要的是一个可重复的默认不同的默认实例。我可以这样做:
list_of_dds = [defaultdict(list) for i in xrange(n)]
但是我觉得这里使用列表理解有点脏。我认为这是一种更好的方法。在那儿?请告诉我它是什么。
编辑:
这就是为什么我觉得列表理解不是最理想的。我通常不是预优化类型,但我无法忽略速度差异:
>>> timeit('x=[string.letters]*100', setup='import string')
0.9318461418151855
>>> timeit('x=[string.letters for i in xrange(100)]', setup='import string')
12.606678009033203
>>> timeit('x=[[]]*100')
0.890861988067627
>>> timeit('x=[[] for i in xrange(100)]')
9.716886043548584
答案 0 :(得分:2)
使用列表推导的方法是正确的。为什么你觉得它很脏?你想要的是一个长度由一些基本集定义的事物列表。列表推导基于某些基本集创建列表。在这里使用列表理解有什么问题?
编辑:速度差异是您尝试做的直接后果。 [[]]*100
速度更快,因为它只需要创建一个列表。每次创建一个新列表都比较慢,是的,但如果你真的需要100个不同的列表,你必须期望它更慢。
(它不会在你的字符串示例上每次创建一个新的字符串,但它仍然较慢,因为列表理解不能提前“知道”所有元素将是相同的,所以它仍然必须每次都重新评估表达式。我不知道列表comp的内部细节,但是可能还有一些列表调整大小的开销,因为它不一定知道可迭代的索引的大小,所以它不能预先分配列表。此外,请注意,您的字符串示例中的一些减速是由于在每次迭代时查找string.letters
。在我的系统上使用timeit.timeit('x=[letters for i in xrange(100)]', setup='from string import letters')
代替---查找string.letters
只有一次---将时间减少约30%。)
答案 1 :(得分:1)
列表理解正是你应该使用的。
列表乘法的问题是创建了包含单个可变对象的列表,然后然后尝试复制它。但是,通过尝试从对象本身复制对象,用于创建它的代码不再相关。没有你用做对象会做你想要的,运行用于创建它的代码N次,因为对象不知道用什么代码来创建它。
您可以使用copy.copy或copy.deepcopy来复制它,但这会让您回到同一条船上,因为复制/深度复制的调用只会成为您运行N次所需的代码。
列表理解非常适合这里。怎么了?