首先,对生成器表达式的创建进行计时是没有意义的。创建生成器不会迭代内容,因此速度非常快。找出针对一个元素创建生成器表达式与针对超过 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
在这里,我通过以下方式测试了生成器表达式的迭代尽快丢弃所有元素.
这是因为生成器本质上是一个正在执行的函数,直到它产生一个值,然后暂停,然后再次激活下一个值,然后再次暂停。看“yield”关键字有什么作用?以获得良好的概览。参与此过程的管理需要时间。相反,列表理解不必花费这个时间,它会完成所有循环,而无需为每个生成的值重新激活和停用函数。
发电机是记忆效率高,执行效率不高。它们可以节省执行时间,有时,但通常是因为您避免分配和释放较大的内存块。