python字典扩容触发条件是occupied >= 2/3 * size,其中occupied包含伪空槽;扩容按质数序列选择新大小,非简单翻倍;删除操作产生deleted槽仍计入occupied,可能间接引发扩容;批量插入前预设大小可优化性能。

字典扩容的触发条件
Python字典(dict)在插入新键值对时,若当前装载因子(occupied / size)超过阈值,就会触发扩容。这个阈值不是简单的 2/3,而是由实际已占用槽数(包括被删除但尚未清理的“伪空槽”)与总槽数之比决定的。当 occupied >= 2/3 * size 时,扩容立即发生。
注意:这里的 occupied 不等于键的数量(len(dict)),因为 del 操作只打上 DELETED 标记,并不立刻释放空间;这些被标记的槽仍计入 occupied,会加速下一次扩容。
扩容时的新大小计算规则
扩容不是简单翻倍,而是按预设序列选择下一个“合适”的哈希表大小,该序列由 CPython 源码硬编码,确保容量始终是质数(或特定安全数),以减少哈希冲突:
- 初始大小为 8
- 后续容量依次为:8 → 16 → 32 → 64 → 128 → 256 → 512 → 1024 → 2048 → 4096 → 8192 → …
- 实际增长策略是:新 size = 第一个大于 4 × 当前 size 的“优质容量”(源码中通过查找静态数组实现)
例如:size=8 时,occupied ≥ 6(即 ⌈8×2/3⌉)就扩容;新 size 选 16,而非 12 或 14——因为只有预设的质数级容量才被允许。
立即学习“Python免费学习笔记(深入)”;
删除操作如何间接导致扩容
看似删元素应该减压,但 Python 字典的惰性删除机制反而可能诱发扩容:
- 执行 del d[k] 后,对应槽位变为 DKIX_DUMMY(CPython 3.11+ 中叫 DELETED),仍算作 occupied
- 若反复增删,occupied 居高不下,即使实际键数很少,也会满足扩容条件
- 只有当 resize 发生时,所有 DELETED 槽才会被真正清理,occupied 才回落到真实键数
这是为什么空 dict 占用内存可能远大于预期——历史删除残留了大量伪空槽。
手动控制扩容的实用建议
多数场景无需干预,但以下情况可考虑优化:
- 批量插入前预设大小:如已知要存 1000 个键,可用 dict.fromkeys(keys, None) 或先创建大空字典再赋值,避免多次 resize
- 避免高频增删同一字典:若需频繁动态维护,可定期重建新 dict:d = {k: v for k, v in d.items() if condition},清除 DELETED 槽
- 监控内部状态(调试用):通过 sys.getsizeof(d) 观察内存变化,或用 gc.get_referents(d) 配合底层分析(需 ctypes 或 debug build)










