用yield逐行或分块读取超大文件可避免内存溢出,因生成器仅在迭代时产出数据、内存占用恒定;而readlines()会全量加载文件至内存,易触发memoryerror。

直接用 yield 逐行或分块读取超大文件,能避免内存爆掉——前提是别在生成器里做全量解析或缓存。
为什么不能直接 open().readlines()?
因为 readlines() 会把整个文件加载进内存,哪怕只是 2GB 的纯文本日志,也极可能触发 MemoryError。而生成器本身不保存全部数据,只在每次 next() 或 for 迭代时产出一行(或一块),内存占用基本恒定。
- 典型错误:写
def read_big_file(): return [line.strip() for line in open(...)]——这根本没用yield,还是全量加载 - 正确姿势:函数体里必须有
yield语句,且不能被包裹在列表推导式里 - 注意文件句柄生命周期:用
with open(...) as f:包裹,否则生成器中途抛异常会导致文件未关闭
按行 yield 最简可靠写法
适用于日志、CSV、配置等以行为单位的文本文件,且单行长度可控(比如不超过几 MB)。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
def read_lines(filepath):
with open(filepath, encoding='utf-8') as f:
for line in f: # 文件对象本身是迭代器,天然流式
yield line.rstrip('\n\r')
- 不用
f.readlines(),也不用while True: line = f.readline()——前者全加载,后者易漏空行或 EOF 判断出错 -
line已带换行符,rstrip('\n\r')比strip()更安全,避免误删字段末尾空格 - 如果文件编码不确定,建议加
errors='replace'参数防解码崩溃
按固定大小块 yield(适合二进制或无行结构数据)
当文件没有明确换行(如 protobuf、自定义二进制格式),或某几行特别长(比如含 base64 大字段),按行读可能卡住,此时需按字节块读。
def read_chunks(filepath, chunk_size=8192):
with open(filepath, 'rb') as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
-
chunk_size建议设为 4096–65536 之间:太小导致系统调用频繁;太大则单次内存峰值升高 - 必须用
'rb'模式,避免文本模式下换行符转换干扰字节边界 - 注意:块内可能截断一行或一条记录,后续解析逻辑得自己处理跨块边界情况
常见陷阱:生成器被多次迭代或意外缓存
生成器只能遍历一次,且容易被无意转成列表,让内存优势瞬间归零。
- 错误:写
data = list(read_lines('huge.log'))——又全加载了 - 错误:在
for循环里反复调用同一生成器对象,第二次什么也不产出 - 安全做法:需要多次使用时,要么重新调用生成器函数(
for x in read_lines(...): ...),要么显式传入iter()并确认上游不缓存 - 调试时慎用
print(list(gen)),它会一次性耗尽生成器并吃光内存
真正难的不是写出 yield,而是确保整个数据流链条——从读取、解析、过滤到写入——都保持惰性。一旦中间某个环节调用了 list()、sorted() 或 pandas read_csv() 这类全量函数,前面的努力就白费了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










