举个例子
>>> from timeit import timeit
>>> print(timeit('[y for y in range(100)]', number=100000))
0.7025867114395824
>>> print(timeit('(y for y in range(100))', number=100000))
0.09295392291478244
>>> print(timeit('set([y for y in range(100)])', number=100000))
1.0864544935180334
>>> print(timeit('set((y for y in range(100)))', number=100000))
1.1277489876506621
这很困惑。生成器创建所需的时间更少(这是可以理解的),但为什么将生成器转换为集合比转换列表慢(至少据我所知)恰恰相反。
请您参考如下方法:
首先,对生成器表达式的创建进行计时是没有意义的。创建生成器不会遍历内容,因此速度非常快。找出在一个元素上创建生成器表达式与在超过 1000 万个元素上创建生成器表达式之间的区别:
>>> print(timeit('(y for y in range(1))', number=100000))
0.060932624037377536
>>> print(timeit('(y for y in range(10000000))', number=100000))
0.06168231705669314
生成器需要比列表对象更多的时间来迭代:
>>> from collections import deque
>>> def drain_iterable(it, _deque=deque):
... deque(it, maxlen=0)
...
>>> def produce_generator():
... return (y for y in range(100))
...
>>> print(timeit('drain_iterable(next(generators))',
... 'from __main__ import drain_iterable, produce_generator;'
... 'generators=iter([produce_generator() for _ in range(100000)])',
... number=100000))
0.5204695729771629
>>> print(timeit('[y for y in range(100)]', number=100000))
0.3088444779859856
在这里,我仅通过 discarding all elements as fast as possible 测试了生成器表达式的迭代.
这是因为生成器本质上是一个函数,一直执行到它产生一个值,然后暂停,然后为下一个值再次激活,然后再次暂停。参见 What does the "yield" keyword do?以获得良好的概述。涉及此过程的管理需要时间。相比之下,列表理解不必花费这段时间,它会循环执行所有操作,而不会为每个产生的值重新激活和停用函数。
生成器内存效率高,但执行效率不高。它们可以节省执行时间,有时,但通常是因为您要避免分配和释放更大的内存块。
