需要注意的是 3.8 版本实现中,Dict 的结构较之前版本有一些调整。
typedef struct {
PyObject_HEAD // Python 对象的头部信息
Py_ssize_t ma_used; // 字典中元素数量
uint64_t ma_version_tag; // 全局状态,用来表示所有字典的变化
PyDictKeysObject *ma_keys; // 字典的 keys,在 combined 模式下也存储 values
PyObject **ma_values; // values 数组,仅在 splitted 模式下有效。
} PyDictObject;
其中 PyObject_HEAD 是所有 Python 对象必备的元信息;ma_version_tag 会随着对 Dict 类的操作而自增,表示是否对字典做过修改;ma_keys 和 ma_values 比较特殊,为了降低内存分配调用,字典的 key-value 可能连续的存储在 ma_keys 中,或者 values 单独存储在 ma_values 中。它看起来会是这样子:
图中也将 PyDictKeysObject 的细节也绘制出来了,就不再赘述。需要注意的是,dk_indices 就是 Dict 的散列表
其中 PyDictKeyEntry 的结构如下,
typedef struct {
Py_hash_t me_hash;
PyObject *me_key;
PyObject *me_value;
} PyDictKeyEntry;
me_hash 是 me_key 哈希的缓存,减少哈希函数的调用。
这里变量为什么要用 m* 呢?我觉得有可能是 map 的意思,难道早期 Dict 就被称为 Map?有知道的朋友不吝赐教。