0

我需要初始化一个默认字典列表。如果他们是,比如说,字符串,这将是整洁的:

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
4

2 回答 2

2

您使用列表理解的方法是正确的。为什么你觉得它很脏?您想要的是一个长度由某个基本集定义的事物列表。列表推导式基于某些基本集创建列表。在这里使用列表理解有什么问题?

编辑:速度差异是您尝试做的直接后果。 [[]]*100更快,因为它只需要创建一个列表。每次创建一个新列表都比较慢,是的,但是如果你真的想要 100 个不同的列表,你必须期望它会更慢。

(它不会每次在您的字符串示例上创建一个新字符串,但它仍然较慢,因为列表理解不能提前“知道”所有元素都将是相同的,所以它仍然必须每次都重新评估表达式。我不知道列表组合的内部细节,但可能还有一些列表调整开销,因为它不一定知道可迭代的索引的大小,所以它可以t 预先分配列表。此外,请注意,您的字符串示例中的一些减速是由于string.letters每次迭代都进行查找。在我的系统上,timeit.timeit('x=[letters for i in xrange(100)]', setup='from string import letters')改为使用 --- 只查找string.letters一次 --- 将时间减少了大约 30%。 )

于 2012-07-25T21:42:21.780 回答
1

列表理解正是您应该使用的。

列表乘法的问题是创建了包含单个可变对象的列表,然后您尝试复制它。但是通过尝试从对象本身复制对象,用于创建它的代码不再相关。您对对象所做的任何事情都不会做您想做事情,即运行用于创建它的代码 N 次,因为该对象不知道用于创建它的代码是什么。

你可以使用 copy.copy 或 copy.deepcopy 来复制它,但这会让你回到同一条船上,因为那时对 copy/deepcopy 的调用就变成了你需要运行 N 次的代码。

列表推导非常适合这里。它出什么问题了?

于 2012-07-25T21:59:29.843 回答