将生成器视为惰性序列,它通常作为相应的急切序列的时间效率较低。
%timeit sum((x*2 for x in range(5000))) # lazy generator
366 µs ± 9.24 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit sum([x*2 for x in range(5000)]) # eager list
308 µs ± 3.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这是因为生成器保持中间状态,必须为每个项目恢复。相反,急切地创建一个序列只需要处理一次中间状态。
但是请记住,生成器的开销基本上是固定的。如果每个项目都需要很长时间来计算,那么生成器的恒定开销就可以忽略不计。当一次处理一个项目时,s 还允许释放已处理的项目,从而减少流程的整体负载——可能在某个时候达到净时间优势。
生成器的优点是惰性允许表示无限序列和延迟 ——与序列“普通 O(ni)”相比,生成器是“n 倍 O(i)”。这允许生成器以可靠的时间效率生产每个项目,即使整个过程会无限延迟。
一个无限的、急切的序列将具有无限的时间复杂度,但一个无限的惰性生成器只根据需要生成项目。
def randoms():
"""Infinite stream of random numbers"""
while True:
yield random.random()
同样,生成器允许外部数据源在提供每个项目之间有时间。当数据源在提供项目之间存在显着延迟时,这可以使生成器更高效。