列表推导式比for+append快50%以上,因其预分配内存、避免属性查找、减少字节码指令;嵌套循环顺序不可颠倒;条件if仅作用于左侧已定义变量;含副作用或复杂逻辑时应避免使用。

list 构建慢?用列表推导式通常能提速 50% 以上,但前提是写对——它不是语法糖,而是 C 层优化的原生结构。
为什么列表推导式比 for + append 快?
Python 解释器对 [expr for item in iterable] 做了底层优化:预分配内存、避免重复的属性查找(如 list.append)、减少字节码指令数。而传统循环中每次 .append() 都要解析方法名、查属性、调用函数,开销明显。
-
for循环里调用append是纯 Python 函数调用,每次都有栈帧开销 - 列表推导式在创建时就知道最终长度(可预测迭代次数),内部直接 malloc 内存块
- 没有中间变量、无额外命名空间查找,表达式直接编译为紧凑字节码
嵌套循环必须用双 for,顺序不能颠倒
写 [num for row in matrix for num in row] 是展平二维列表;如果写成 [num for num in row for row in matrix],会报 NameError: name 'row' is not defined —— 因为变量作用域按从左到右声明,row 必须先于 num 出现在 for 子句中。
- 外层
for在前,内层for在后,对应传统嵌套循环的缩进层级 - 条件
if可放在任意for后,但只作用于它前面所有已定义的变量 - 例如
[(i,j) for i in range(3) for j in range(3) if i != j]中,i和j都已定义,条件才有效
带函数调用时,注意副作用和类型安全
像 [int(x) for x in str_list if x.isdigit()] 看似简洁,但 isdigit() 对负数、小数字符串返回 False,而 int() 本身可能抛异常(虽然这里被 if 挡住了)。实际中更常见的是 try/except 场景,但列表推导式不支持 try 块。
- 别在推导式里放有副作用的函数(如
print()、修改全局状态),逻辑难追踪 - 避免嵌套多层函数调用,比如
[f(g(h(x))) for x in data],可读性差且调试困难 - 若需容错转换,优先用辅助函数封装,再在推导式中调用:
safe_int = lambda s: int(s) if s.isdigit() else None
什么时候不该用列表推导式?
三个典型反例:需要多次遍历结果、逻辑分支超过两层、或数据量极大但只消费一次。
- 生成的列表后续要反复索引或多次遍历?没问题——但若只用于
sum()或any(),用生成器表达式(...)更省内存 -
if-elif-else多分支?硬塞进推导式会变成[a if c1 else b if c2 else d for ...],立刻变面条代码 - 处理 GB 级日志行?别用
[process(line) for line in big_file],改用(process(line) for line in big_file)或分块读取
真正容易被忽略的点是:列表推导式一旦执行就完成全部计算,没有懒求值能力。哪怕你只取前 5 个元素,它也把整个列表全算出来。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











