“按需计算”或惰性计算随着处理数据量的增长而变得流行。在Python中,这些机制通过生成器和迭代器在标准库中实现,后来又通过itertools函数和能够按需返回单个元素的类实现,从而避免了将所有数据一次性存储在内存中。
常规的集合构建需要将整个结果加载到内存中。如果数据量很大,程序可能会崩溃或运行得非常慢。能够处理数据流是重要的,例如处理数GB的文件或对API的请求结果。
惰性计算允许根据需要获取元素。在Python中,这通过使用生成器、yield语法、生成器表达式、map、filter、zip函数以及itertools模块等实现。这种方法基于迭代器协议。
代码示例:
def huge_sequence(): for i in range(1, 10**9): yield i * i for val in huge_sequence(): if val > 100: break print(val)
关键特性:
在Python中,生成器是否总是节省内存?
答案:不,只有在数据确实不需要在步骤之间进行中间存储时。某些构造,例如列表推导,会立即创建整个列表,而生成器则是按需生成的。如果仍然需要中间结果,节省将会失去。
示例:
squares = (x**2 for x in range(10**8)) # 惰性,节省内存 result = list(squares) # 会立即消耗所有内存
map和filter总是返回列表是否正确?
不,在Python 3中,map和filter返回的不是列表,而是迭代器(惰性生成器),这节省了内存并允许“实时”处理数据。
是否可以多次迭代生成器?
不,生成器在完全遍历后会“耗尽”。如果需要重新遍历,则需要创建新的生成器或使用可以多次遍历的容器集合。
开发人员尝试通过将大的日志文件作为字符串列表加载到内存中来处理它。
优点:
缺点:
使用生成器——逐行读取文件,并在接收每一行时进行处理。
优点:
缺点: