dictobject.h
PyDictObject是一种字典类型,从可哈希的对象映射到另一个对象。
然后提到了在Objects目录下,有dictnotes.txt文件,关于字典的使用设计和优化。
字典类实际上是维护了一张哈希表,而表项,entry or slot,有3种状态。
1. Unused. me_key == me_value == NULL
未使用状态,key和value都为空。
这是表项的初始状态,仅当初始时key才会为空。
2. Active. me_key != NULL and me_key != dummy and me_value != NULL
正在使用状态,key不为空且不为dummy,value不为空。
3. Dummy. me_key == dummy and me_value == NULL
曾使用状态,但该表项已经被删除了。key为dummy,value为空。
设置Dummy状态是因为Python面对hash冲突时所采取的是开放地址法,会再次寻找位置。
所以会产生探索链这样的关联结构,比如A、B、C三者的哈希值一样,那么会处在一条探索链上。
当B被删除后,为了保证能够搜索到C,特地设置Dummy值,表示后面还可能存在有效表项。
#define PyDict_MINSIZE 8
PyDict_MINSIZE是一个字典的最小大小,这个“小字典”是直接作为表项的成员的,ma_smalltable。
表项的结构如下:
typedef struct {
/* Cached hash code of me_key. Note that hash codes are C longs.
* We have to use Py_ssize_t instead because dict_popitem() abuses
* me_hash to hold a search finger.
*/
Py_ssize_t me_hash;
PyObject *me_key;
PyObject *me_value;
} PyDictEntry;
由注释可以知道me_hash的一个作用是避免重复计算,另一个作用是可以用来指向探索链的下一个。
字典的结构如下:
typedef struct _dictobject PyDictObject;
struct _dictobject {
PyObject_HEAD
Py_ssize_t ma_fill; /* # Active + # Dummy */
Py_ssize_t ma_used; /* # Active */
/* The table contains ma_mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
Py_ssize_t ma_mask;
/* ma_table points to ma_smalltable for small tables, else to
* additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and
* setitem calls.
*/
PyDictEntry *ma_table;
PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash);
PyDictEntry ma_smalltable[PyDict_MINSIZE];
};
由注释可知ma_fill和ma_used的含义。
ma_mask经常用来与key的哈希值进行与运算,使其落在表的范围内。
ma_table指向ma_smalltable或者另外分配的内存。
为了保证在表中搜索位置的过程会终止,表中至少有一项Unused。
另外为了避免低效搜索,当有三分之二的表项被使用了,会重新调整表的大小。
JasonLee 2011.08.14 23:35 明天又周一了,今天大连散步