python列表扩容采用几何增长策略,当size==allocated时触发,新容量≈size×1.125+偏移(小列表+3,大列表+6),通过realloc重分配指针数组,保持append平均o(1)时间复杂度。

Python列表(list)的扩容机制,本质上是通过预分配额外内存来平衡时间效率与空间开销。它不每次追加都重新分配,而是采用“几何增长”策略,在底层 C 实现中动态调整数组容量(allocated),使 append() 平均时间复杂度保持 O(1)。
扩容触发条件
当执行 append()、insert() 或其他需增加元素的操作时,若当前已用长度(size)等于已分配容量(allocated),就会触发扩容:
- 不是“满即扩”,而是
size == allocated时才申请新内存 -
extend()批量添加时,若预估总长度超过当前allocated,也会提前扩容(可能一次到位) - 空列表首次
append会直接分配小块内存(通常为 0 或 4 个指针大小)
增长公式:近似 1.125 倍 + 小偏移
CPython 源码中实际使用的是以下逻辑(简化版):
new_allocated = (size >> 3) + (size < 9 ? 3 : 6)
即:新容量 ≈ 当前已用长度 × 1.125 + 偏移量(小列表加 3,大列表加 6)。这不是严格的等比数列,而是兼顾小列表起步和大列表渐进增长的启发式策略:
立即学习“Python免费学习笔记(深入)”;
- 从 0 → 4 → 8 → 12 → 16 → 20 → 25 → 32 → 39 → 48 … 逐步上升
- 避免频繁小步扩容,也防止过度预留(如翻倍会导致大量闲置内存)
- 可通过
sys.getsizeof([])和反复append后观察__sizeof__()变化验证
内存重分配与数据迁移
扩容时会调用 C 的 realloc()(或 malloc+memcpy)完成三件事:
- 申请一块更大的连续内存区域(存储的是
PyObject*指针,非对象本体) - 将原有指针数组内容逐个复制过去(浅拷贝,不复制对象)
- 释放旧内存块;原列表对象的
ob_item指针指向新地址
注意:该过程是原子的,但若内存不足会抛出 MemoryError;且扩容期间列表仍可被其他引用访问(因对象 ID 不变,仅内部指针更新)。
如何查看和影响扩容行为
无法直接控制增长系数,但可以间接观察和优化:
- 用
list.__sizeof__()查看当前占用字节数(含预留空间) - 用
len(lst)和估算容量差值,反推是否刚扩容(如len==allocated时下次 append 必扩容) - 若预先知道最终长度,可用
[None] * n初始化,或调用list.extend(iterable)替代循环append -
list.clear()不释放内存(allocated保持不变),适合复用;真正释放需重新赋值或del lst[:]后 GC










