嵌套列表推导式吃内存是因为每层都会立即生成完整列表,两层嵌套即创建“外层×内层”个对象;改用生成器表达式(如(()))或itertools.product可延迟计算、节省内存。

嵌套列表推导式为什么会吃内存?
因为每次执行 [... for ... in ...] 都会立即生成一个完整的新列表,嵌套两层就相当于构建了「外层长度 × 内层长度」个元素的中间列表。比如 [[x*y for y in range(1000)] for x in range(1000)] 会一次性分配 100 万个 int 对象,且全部驻留内存。
用生成器表达式替代内层列表推导
把内层 [] 换成 (),就能让内层不立刻展开,只在需要时产出值。这特别适合后续要逐个处理、过滤或只取前 N 项的场景。
示例对比:
bad = [[x+y for y in range(1000)] for x in range(1000)] # 占约80MB内存 good = ((x+y for y in range(1000)) for x in range(1000)) # 几乎不占额外内存
- 注意:
good是生成器的生成器,不能直接索引或切片,只能迭代 - 如果后续要用
sum()、any()或itertools.islice(),这种结构反而更快更省 - 若必须转成列表(比如要多次遍历),再调用
list()—— 但请确认是否真有必要
用 itertools.product 扁平化多层嵌套
当嵌套逻辑本质是笛卡尔积(比如遍历所有 (i,j,k) 组合),硬写三层推导式不仅难读,还容易触发嵌套列表膨胀。用 itertools.product 可以一步拉平,并返回迭代器。
例如替代:
[(i,j,k) for i in A for j in B for k in C]
换成:
Python 编程规范与最佳实践。强制 PEP 8 代码风格、语法校验、单元测试执行,适用于代码编写、审查和重构。触发词:Python、代码规范、py_compile、单元测试。
import itertools itertools.product(A, B, C) # 返回迭代器,不预生成全部元组
-
product支持repeat=参数,如product(range(3), repeat=4)等价于四层嵌套 - 它比手写嵌套推导式省内存,也更容易加条件过滤(配合
filter()) - 注意:
A、B、C若是生成器,product会将其转为元组缓存 —— 所以输入尽量用list或小序列
提前终止和条件短路能省多少内存?
生成器天然支持短路,但很多人忘了在推导式里用 if 条件过滤掉大量无效项,反而让无用中间结果塞满内存。
错误写法:
process(x)
正确做法(尤其当 process() 开销大或返回大对象时):
[process(x) for x in (y for y in big_data if condition(y))]
- 外层仍是列表推导,但内层生成器先筛数据,
process()只对符合条件的调用 - 如果最终只需要第一个匹配项,直接用
next((process(x) for x in big_data if condition(x)), None) - 别依赖「Python 3 的列表推导式作用域隔离」来规避变量泄漏 —— 它不影响内存行为
真正决定内存用量的,不是「写法多炫」,而是「什么时候构造对象」和「构造几个」。嵌套越深,越要问自己:这一层真的需要立刻全量实例化吗?
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










