列表推导式在简单映射/过滤时更快,因字节码用LIST_APPEND而非CALL_FUNCTION;嵌套循环时反而慢15–20%;含I/O、复杂条件、控制流或大数据量时应避免。

列表推导式在绝大多数简单映射/过滤场景下确实更快,但不是“永远更快”——关键差异在字节码层面,而选型要看数据规模、逻辑复杂度和可维护性。
LIST_APPEND 字节码 vs CALL_FUNCTION 开销
列表推导式快的核心原因不是语法糖,而是解释器生成的字节码不同:LIST_APPEND 是 C 层直接操作列表对象的指令,不经过 Python 层的方法查找和函数调用;而 for 循环中每次 result.append(...) 都要执行 LOAD_ATTR(找 append 方法)+ CALL_FUNCTION(调用它),多出约 20–40 µs 的开销(实测于 Python 3.11+)。
你可以用 dis 验证:
import dis
dis.dis("[x*2 for x in range(10)]")
dis.dis("r=[]; [r.append(x*2) for x in range(10)]") # 注意:这其实还是推导式,真对比得写纯 for
真正对比时,应写:
r = []
for x in range(10):
r.append(x*2)
它的字节码里会出现明确的 CALL_FUNCTION 指令,而推导式没有。
嵌套循环时列表推导式反而更慢
当出现两层及以上 for 子句(如 [[i+j for j in range(m)] for i in range(n)]),推导式不仅没提速,还可能比等效 for 循环慢 15–20%(实测 1000×1000 矩阵生成)。
- 原因:嵌套推导式会触发多次内部列表构造与内存分配,且无法复用局部变量优化
-
for循环可以提前声明外层列表、重用内层临时变量,控制更精细 - 若涉及 NumPy 或 Pandas,直接跳过两者,用
np.zeros((n, m))+ 向量化赋值,快一个数量级
什么时候该放弃列表推导式
以下情况强行用列表推导式会埋坑:
- 表达式中调用含 I/O、数据库查询或复杂计算的函数(如
[fetch_user(x) for x in ids])——无法短路、难以调试、错误堆栈不友好 - 条件分支超过 3 个嵌套(
if a and b and not c and d in xs)——可读性断崖下跌,同事第一眼看不懂 - 需要
break/continue/ 异常处理逻辑 —— 推导式不支持这些控制流 - 结果不需要一次性全加载进内存(比如处理千万行日志)——此时该用生成器表达式
(x*2 for x in big_iter),而非方括号
选型决策树:三步判断
面对一个新需求,快速决定用不用列表推导式:
- 输入是小到中等规模(if 和单层
for?→ 优先用推导式,清晰又快 - 有嵌套、含副作用函数、或需中间状态(如计数器、缓存)?→ 写
for循环,加注释说明意图 - 数据量大或后续要继续管道化处理?→ 直接上生成器表达式或
itertools,别急着转成 list
最易被忽略的一点:性能瓶颈 rarely 在列表构建本身,而在你推导式里调用的那个 transform() 函数——优化它,比换推导式有用十倍。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











