generator 是处理长序列时避免 memoryerror 的必要手段,它通过 yield 实现惰性计算,仅在迭代时生成单个值并释放内存,不缓存全部结果。

Generator 不是“省点内存”的可选项,而是处理长序列时避免 MemoryError 的必要手段。它不缓存全部结果,只在 next() 或 for 迭代时算一个值、交一个值、忘一个值。
生成器函数 vs 列表函数:一次调用就暴露本质差异
写一个返回前一百万个平方数的函数,列表版会立刻吃掉几百 MB 内存;生成器版启动时几乎零开销:
- 列表函数:
def squares_list(n): return [x*x for x in range(n)]—— 调用即分配完整列表 - 生成器函数:
def squares_gen(n): for x in range(n): yield x*x—— 调用只返回generator对象,不执行循环体
关键区别不在语法,而在执行时机:yield 让函数变成“暂停-恢复”状态机,局部变量(如 x)被 Python 自动挂起保存,不需要你手动维护计数器或索引。
生成器表达式:最简写法,但别误当列表用
(x*x for x in range(10**7)) 看起来像列表推导式,只是括号不同——但这点差异决定内存命运:
- 它不生成任何值,直到第一次
next()或进入for循环 - 不能用
len()、squares_gen[5]或多次遍历:生成器耗尽后再次迭代直接抛StopIteration - 若你需要重复使用,要么重新调用生成器函数,要么明确转成
list(仅当确认数据量可控)
常见误操作:data = (process(x) for x in big_list); list(data); list(data) —— 第二个 list() 得到空列表,因为生成器已枯竭。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
大文件逐行处理:yield 是唯一合理姿势
读 5GB 日志文件时,open().readlines() 或 list(f) 会尝试把全部文本塞进内存,大概率触发 MemoryError。正确路径只有一条:
- 用
for line in f:本身已是惰性迭代,但封装成生成器更清晰、可复用、易测试 - 示例:
def read_log_lines(path): with open(path) as f: for line in f: yield line.rstrip('\n') - 注意:必须在生成器内部
with open,否则文件句柄在生成器对象创建后就关闭了,后续next()会报ValueError: I/O operation on closed file
这个模式可无缝嵌套:filter_errors = (line for line in read_log_lines('app.log') if 'ERROR' in line),整条链仍保持常量内存占用。
yield from 构建数据管道:避免中间容器膨胀
当你需要串联多个数据源或处理阶段(比如配置 + 分隔符 + 日志行),用 yield from 直接委托子生成器,不引入额外列表:
- 错误方式:
return list(read_config()) + ['---'] + list(read_data())—— 全部加载进内存再拼接 - 正确方式:
def pipeline(): yield from read_config(); yield '---'; yield from read_data() - 每个
yield from后续的子生成器也按需驱动,没有中间聚合步骤
这种写法天然适配 ETL 场景,但要注意:一旦某个子生成器抛异常,整个管道中断,需在合适层级加 try/except,而不是指望外层“重试整个生成器”——它不可重入。
TypeError: can't pickle generator objects,这时候得换用 queue 或临时文件中转。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










