循环中append()变慢主因是列表扩容(约1.125倍)引发内存重分配与元素拷贝,数十次扩容导致非线性耗时;预分配推荐[None]n或列表推导式,避免误用[[0]n];构造DataFrame优先用list[tuple]并显式指定columns和dtype。

为什么循环中 append() 会变慢?
不是 append() 本身慢,而是 Python 列表在容量不足时会触发扩容:每次扩容约 1.125 倍(CPython 实现),涉及内存重新分配 + 元素逐个拷贝。如果循环几万次,可能触发数十次扩容,实际耗时远超线性增长。
更隐蔽的问题是:如果循环体里还涉及字符串拼接、字典构造或临时对象创建,GC 压力也会明显上升,进一步拖慢整体节奏。
预分配列表的两种可靠做法
预分配的关键是「提前知道长度」。如果确实已知行数(比如读固定 CSV 行、遍历确定长度的 range 或 zip),优先用 [None] * n;否则改用列表推导式,它本质是单次预分配 + 填充,比循环 append 更快也更 Pythonic。
- 已知长度
n:用results = [None] * n,再用索引赋值:results[i] = (x, y, z) - 未知长度但逻辑清晰:直接写成列表推导式,例如
[(f(x), g(x)) for x in data],解释器会自动优化 - 避免误用
[[0] * n]—— 这只生成一个子列表的引用副本,修改任一元素会“连锁反应”
从预分配列表到 DataFrame 的高效转换
pd.DataFrame() 构造函数对输入结构敏感:传入 list of tuples / list of lists 最快;传入 list of dicts 会多一层字段对齐开销;若用 pd.concat([pd.Series(...), ...]) 拼接,性能断崖式下跌。
立即学习“Python免费学习笔记(深入)”;
- 推荐结构:预分配为
list[tuple]或list[list],列顺序与目标 DF 列名严格一致 - 构造时显式指定
columns=,避免 pandas 自动推断类型(尤其混合类型时易转成object) - 如果原始数据含大量
None或np.nan,建议构造后立刻调用df.astype(...)显式设 dtype,防止后续计算意外升格为 object
data = [None] * len(items)
for i, item in enumerate(items):
data[i] = (item.id, item.name, item.score)
df = pd.DataFrame(data, columns=['id', 'name', 'score'])什么情况下不该预分配?
预分配不是银弹。当循环逻辑导致「是否追加」需动态判断(如过滤、异常跳过、嵌套条件),硬套预分配反而让代码难读且易错——你得额外维护计数器、处理空位、最后还要切片去 None。
此时更务实的做法是:用普通 append(),但把最终构造 DF 的动作延迟到循环结束,并确保收集的是扁平结构(别嵌套 dict inside list inside tuple)。
真正影响性能的,从来不是 append 这一行,而是数据结构混乱 + 类型不稳 + 多余的中间转换。盯着预分配不如先确认你的 data 列表里每个元素是不是长得一模一样。


















