Python字典核心底層原理

字典核心底層原理(是很重要的)

一.存儲鍵值對過程

       字典對象的核心是散列表,散列表是一個稀疏數組(總是有空不元素的數組),數組的每一個單元叫做bucket(或叫桶.表元),每一個bucket有兩部分,一個是鍵對象的引用,一個是值對象的引用,

       由於,所有bucket結構和大小一致,可以通過偏移量來讀取指定bucket。

                                    

      將一個鍵值對放在字典的底層過程:

                 >>>a={}

                 >>>a['name']='tianya'

      假設字典a對象創建完成後,數組長度爲8:

                        

     要把“name”=“tianya”,這個鍵值對放到字典對象a中,首先第一步需要計算鍵“name”的散列值,python中可以通過hash()來計       算。

      >>>bin(hash('name'))

      '0b11111111101110101000001110001111101010110100011000011111110'

      由於數組長度爲8,可以拿計算出的散列值得最右邊3位數作爲偏移量,即"110",十進制數字是 6,我們查看偏移量6,對應的bucket是否爲空,如果爲空,則將鍵值對放進去,如果不爲空,則依次取右邊3位作爲偏移量,即“111”,十進制是數字7,再查看偏移量爲7的bucket是否爲空,如果爲空,則放進去,直到找到爲空的bucket將鍵值對放進去。

      流程圖如下:

      

    擴容:

            Python會根據散列值列表的擁擠程度擴容,“擴容”指的是創造更大數組,將原有內容拷貝到新的數組中。

            接近2/3時,數組就會擴容。

二.根據鍵查找“鍵值對”的底層過程

    理解了,一個鍵值對是如何存儲到數組中的,根據鍵對象取到值對象,理解起來就簡單多了。

    >>>a.get('name')

    tianya

    當調用a.get('name'),就是根據鍵“name”查找到“鍵值對”,從而找到值對象“tianya”

    第一步,仍然要計算“name”對象的散列值:

                   >>>bin(hash('name')

                   '0b11111111101110101000001110001111101010110100011000011111110'

    和存儲的底層算法一致,也是依次取散列值的不同位置的數字。假設數組長度爲8.我們可以拿計算出的散列值的最後邊3位數字做完偏移量,即“110”,十進制數字是6,查看偏移量6,對應的bucket是否爲空,如果爲空,則返回None。如果不爲空,則返回這個bucket的鍵對象計算對應散列值,和我們的散列值進行比較,如果相等,則將對應“值對象”返回,如果不相等,則再次依次取其他幾位數字,重新計算偏移量,依次取完後,仍然沒有找到,則返回None,流程如下:

     

用法總結一下:

1.鍵必須可散列:

   1>數字、字符串、元組都是可以散列的

   2>自定義對象需要支持下面三點:

       1)支持hash()函數

       2)支持通過__eq__()方法檢測相等性

       3)若a==b爲真,則hash(a)==hash(b)也爲真

2.字典在內存中開銷巨大,典型的空間換時間

3.鍵查詢速度很快

4.往字典裏面添加新建可能導致擴容,導致散列表中鍵的次序發生變化,因此,不要在遍歷字典的時候同時進行字典的修改。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章