python學習筆記 關於字典

字典

dict類型是python語言的基石,因此python對於dict類型實現了高度優化,而 散列表 則是字典類型性能突出的根本緣由。python

什麼是可散列的數據類型

定義:若是一個對象是可散列的,那麼在這個對象的生命週期中,它的散列值是始終不變的,並且這個對象一定實現__hash__()方法。 另外,可散列對象還必須實現 __eq__()方法,這樣才能保證兩個相同類型的對象能夠進行比較。若是兩個對象是相同的,那麼它們的散列值必定是相同的。app

也就是說,一個可散列對象必須同時知足如下三個條件:性能

  1. 支持hash()方法,而且經過__hash__()方法所得到的散列值是不變的;
  2. 支持經過__eq__()方法來判斷兩個對象的值是否相等;
  3. 若 a==b,則必有 hash(a) == hash(b)。
  • 原子不可變數據類型(str、bytes和數值類型)都是可散列類型;
  • frozenset類型也是可散列的;
  • 當一個元組中所包含的值都是可散列的,該元組纔是可散列的。

下例展現了建立字典的不一樣方式優化

>>> d1 = dict(one=1, two=2, three=3)
>>> d2 = {'one':1, 'two':2, 'three':3}
>>> d3 = dict(zip(['one', 'two', 'three'], [1,2,3]))
>>> d4 = dict([('two', 2), ('one', 1), ('three', 3)])
>>> d5 = dict({'one':1, 'two':2, 'three':3})
>>> d1 == d2 == d3 == d4 == d5
True

處理找不到的鍵

假設有一個字典dict,當程序試圖查找一個不存在的鍵值 dict[k] 時,會拋出一個異常KeyError,這個行爲複合python所信奉的「快速失敗」哲學。固然,咱們能夠採用dict.get(k, default)來代替dict[k],當找不到鍵k時,返回默認值default,可是,這並非一個高效的方式,也不是一個可取的方法。code

1. setdefault方法

下面是一個案例:對象

dict_demo = {}
print(dict_demo)
key = "name"
dict_demo.get(key)
dict_demo.setdefault(key, [])  
print(dict_demo)
dict_demo.setdefault("pass", "123456")
print(dict_demo)

運行結果以下:three

{}
{'name': []}
{'name': [], 'pass': '123456'}

代碼中第一個 setdefault 中未找到 key,因而把一個空列表賦值到該鍵值生命週期

第二個 setdefault 未找到鍵"pass",將一個字符串賦值給該鍵ip

通過兩個setdefault以後,該字典含有兩個鍵值對,該方法主要用於對字典進行更新字符串

2.defaultdict 處理空缺鍵的一個選擇

在用戶建立defaultdict對象時,須要給它配置一個爲找不到的鍵創造默認值的方法

具體而言,就是在實例化一個defaultdict對象時,須要給構造方法賦予一個可調用對象,這個可調用對象在__getitem__碰到找不到的鍵時,讓__getitem__返回一個默認值。

key = "name"
dict_demo2 = collections.defaultdict(list)
print(dict_demo2)
dict_demo2[key].append((1,2))
print(dict_demo2)
dict_demo2["pass"]
print(dict_demo2)

運行結果:

defaultdict(<class 'list'>, {})
defaultdict(<class 'list'>, {'name': [(1, 2)]})
defaultdict(<class 'list'>, {'name': [(1, 2)], 'pass': []})

dict_demo2一開始是一個空字典,不存在任何鍵值,當運行dict_demo2[key]時,其中包含一下三個步驟:

(1) 調用list()建立一個新列表

(2) 把這個新列表做爲值,key做爲鍵,放入dd中

(3) 返回這個列表的引用(這也是可以進行append操做的緣由)

若是在鍵值不肯定的狀況下能夠考慮使用defaultdict

3 特殊方法__missing__

全部映射類型在處理找不到的鍵時,都會牽扯__missing__方法,當__getitem__操做找不到鍵值時,就會調用__missing__方法,而不是直接拋出異常。

  • __missing__方法只會被__getitem__方法調用

    class StrKeyDict0(dict):

    def __missing__(self, key):
         if isinstance(key, str):
             raise KeyError(key)
         return self[str(key)]
    
     def get(self, key, default=None):
         try:
             return self[key]
         except KeyError:
             return default
    
     def __contains__(self, key):
         return key in self.keys() or str(key) in self.keys()

    if name == '__main__':

    d = StrKeyDict0([('2', 'two'), ('4', 'four')])
     print(d['2'])
     print(d[4])
     try:
         print(d[1])
     except KeyError:
         print("keyerror")
    
     print(d.get('2'))
     print(d.get(4))
     try:
         print(d.get(1, 'N/A'))
     except KeyError:
         print("keyerror")
    
     print(2 in d)
     print(4 in d)

運行結果:

two
four
keyerror
two
four
N/A
True
True

__missing__方法中將鍵key轉化爲str類型後再次嘗試獲取字典d中相應的鍵值

因此能夠看到,即使字典中沒有 4 這個鍵,可是依然可以正確獲取其在字典中相應的值,可是因爲字典中不存在 1 或 "1" 這樣的鍵,因此沒法獲取d[1]

相關文章
相關標籤/搜索