7

我在 Windows 上使用 Python 3.3.1 64 位和这个代码片段:

len ([None for n in range (1, 1000000) if n%3 == 1])

与此相比,执行时间为 136 毫秒:

sum (1 for n in range (1, 1000000) if n%3 == 1)

执行时间为 146 毫秒。在这种情况下,生成器表达式不应该更快或与列表理解的速度相同吗?

我引用 Guido van Rossum从 List Comprehensions 到 Generator Expressions

...Python 3 中的列表推导和生成器表达式实际上都比 Python 2 中的要快!(并且两者之间不再存在速度差异。)

编辑:

我用 测量了时间timeit。我知道这不是很准确,但我只关心这里的相对速度,当我用不同的迭代次数进行测试时,我的列表理解版本的时间一直在缩短。

4

2 回答 2

7

我相信这里的区别完全在于1000000个添加的成本。在 Mac OS X 上使用 64 位 Python.org 3.3.0 进行测试:

In [698]: %timeit len ([None for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 127 ms per loop
In [699]: %timeit sum (1 for n in range (1, 1000000) if n%3 == 1)
10 loops, best of 3: 138 ms per loop
In [700]: %timeit sum ([1 for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 139 ms per loop

所以,并不是理解比 genexp 快;他们都需要大约相同的时间。但是调用lenalist是即时的,而将 100 万个数字相加会使总时间再增加 7%。

向它抛出几个不同的数字,这似乎可以成立,除非列表非常小(在这种情况下它似乎变得更快),或者足够大以至于内存分配开始成为一个重要因素(它还不是,在 333K)。

于 2013-04-30T19:26:14.197 回答
0

借用这个答案,有两件事需要考虑:

1. Python 列表是可索引的,获取它的长度只需要 O(1) 次。这意味着调用len()列表的速度不取决于它的大小。但是,如果您调用len()生成器,您将消耗它生成的所有项目,因此时间复杂度为 O(n)。

2.见上面的链接答案。列表推导是一个紧密的 C 循环,而生成器必须在内部存储对迭代器的引用并调用next(iter)它生成的每个项目。这为生成器创建了另一层开销。在小范围内,可以安全地忽略列表理解和生成器之间的性能差异,但在更大范围内,您必须考虑这一点。

于 2018-09-03T05:06:19.973 回答