众所周知,python3.6这个版本对dict的实现是做了较大优化的,特别是在内存使用率方面,因此我觉得有必要研究一下最新的dict的源码实现。
前后断断续续看了大概一周多一点,主要在研究dict和创建实例对象那部分的代码,在此将所得记录下来。
值得一提的事,新版的dict使用的算法还是一样的,比如说hash值计算、冲突解决策略(open addressing)等。因此这一部分也不是我关注的重点,我关注的主要是在新的dict如何降低内存使用这方面。
btw,本文的分析是基于python的3.6.1这个版本。
话不多说,先看 PyDictObject结构的定义:
1 typedef struct_dictkeysobject PyDictKeysObject;2
3 /*The ma_values pointer is NULL for a combined table4 * or points to an array of PyObject* for a split table5 */
6 typedef struct{7 PyObject_HEAD8
9 /*Number of items in the dictionary*/
10 Py_ssize_t ma_used;11
12 /*Dictionary version: globally unique, value change each time13 the dictionary is modified*/
14 uint64_t ma_version_tag;15
16 PyDictKeysObject *ma_keys;17
18 /*If ma_values is NULL, the table is "combined": keys and values19 are stored in ma_keys.20
21 If ma_values is not NULL, the table is splitted:22 keys are stored in ma_keys and values are stored in ma_values*/
23 PyObject **ma_values;24 } PyDictObject;
说下新增的 PyDictKeysObject 这个对象,其定义如下:
1 /*See dictobject.c for actual layout of DictKeysObject*/
2 struct_dictkeysobject {3 Py_ssize_t dk_refcnt;4
5 /*Size of the hash table (dk_indices). It must be a power of 2.*/
6 Py_ssize_t dk_size;7
8 /*Function to lookup in the hash table (dk_indices):9
10 - lookdict(): general-purpose, and may return DKIX_ERROR if (and11 only if) a comparison raises an exception.12
13 - lookdict_unicode(): specialized to Unicode string keys, comparison of14 which can never raise an exception; that function can