Python 3.7+ dict 有序是语言规范强制要求,所有合规解释器必须按插入顺序迭代;底层用 entries+indices 双数组实现零开销保序;dict_keys 不支持索引,JSON 保序取决于字典构建方式。

Python 3.7+ dict 有序是语言规范,不是 CPython 特性
它不是“恰好有序”,而是 PEP 558 明确写进 Python 语言规范的强制要求:所有合规解释器(CPython、PyPy、Jython)都必须让 dict 按插入顺序迭代。3.6 及之前版本中看似有序,只是 CPython 的实现细节,文档明确警告“不应依赖”——你在 PyPy 上跑同一段代码,for k in d: 完全可能乱序。
底层靠 entries + indices 双数组结构实现零开销保序
旧版字典用单个稀疏哈希表,扩容重排直接打乱位置;3.7+ 改为两个物理分离的数组:
-
entries:紧凑数组,每次d[key] = value就追加一条(hash, key, value),顺序就是插入时间序 -
indices:稀疏索引数组,只存跳转地址(比如 “这个 hash 槽对应entries第 5 个位置”),负责 O(1) 查找
遍历时直接顺序读 entries,不碰 indices,根本不需要排序逻辑,也不增加内存或 CPU 开销。
为什么 d.keys()[0] 会报错?
dict_keys 是视图对象,不是序列类型,不支持索引:
立即学习“Python免费学习笔记(深入)”;
-
d.keys()[0]→TypeError: 'dict_keys' object is not subscriptable -
list(d.keys())[0]能取第一个键,但触发全量转列表,O(n) 开销,热路径别用 - 真要按位置操作(比如弹出最老项),说明你该用
collections.OrderedDict,它提供popitem(last=False)和move_to_end()
JSON 序列化保序的关键不是 json.dumps(),而是字典怎么构建的
json.dumps() 从不主动排序,它只忠实调用 dict.__iter__()。所以保序前提是你构造的 dict 插入顺序可靠:
- 直接写
{'a': 1, 'b': 2}:CPython 解析器按书写顺序插入,没问题 - 用
{**d1, **d2}:顺序由d1和d2的插入顺序拼接,不是语法顺序 - 从 JSON 反序列化再 dump:3.7+ 的
json.loads()返回有序dict,能保序;但中间若执行d.update({'c': 3}),重复键会覆盖原位置,顺序可能被破坏 -
json.dumps(..., sort_keys=True)会强制按键字母序重排,跟插入顺序无关
最容易被忽略的是:有序是「插入顺序」,不是「定义顺序」或「键大小顺序」。一旦代码隐含了 dict.keys() 等价于 sorted(keys) 的假设,就会在运行时出错——而且很可能只在某些环境或数据下才暴露。


















