閱讀234 返回首頁    go 技術社區[雲棲]


[筆記]PyDictObject頭文件閱讀

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     明天又周一了,今天大連散步

最後更新:2017-04-02 22:16:33

  上一篇:go [筆記]PyDictObject的哈希算法和搜索過程
  下一篇:go [筆記]PyListObject對象