Python系列之Collections內建模組(2),pythoncollections
defaultdict 返回一個類 dict 的對象,defaultdict 是內建的 dict 類的子類。
如果訪問 dict 未初始化的 key 值時,會拋出 KeyError 異常。
1 s_tuple = ('a', 'b', 'a', 'a',2 'c', 'a', 'b', 'a')3 4 c_dict = {}5 6 for s in s_tuple:7 c_dict[s] += 18 9 print(c_dict)
輸出如下:
1 Traceback (most recent call last):2 File "FileNamePath", line 7, in <module>3 c_dict[s] += 14 KeyError: 'a'
對代碼進行修正後如下:
1 s_tuple = ('a', 'b', 'a', 'a', 2 'c', 'a', 'b', 'a') 3 4 c_dict = {} 5 6 for s in s_tuple: 7 if s not in c_dict: 8 c_dict[s] = 1 9 else:10 c_dict[s] += 111 12 print(c_dict)
能夠正常輸出每個 str 出現的統計次數,不過每次迴圈都要進行判斷當前 dict 中是否存在這個 key 值。不過 dict 的 api 中提供了 setdefault() 方法,該方法需提供兩個參數,第一個為 key 值,第二個為該 key 初始狀態下的預設值。如果字典中不存在此 key 值,則該方法返回預設值,反之返回該 key 值對應的 value。
1 s_tuple = ('a', 'b', 'a', 'a',2 'c', 'a', 'b', 'a')3 4 c_dict = {}5 6 for s in s_tuple:7 c_dict[s] = c_dict.setdefault(s, 0) + 18 9 print(c_dict)
下面引入 defaultdict 的用法,defaultdict 類初始化時接收一個類型作為參數,當訪問的 key 值不存在時,可執行個體化傳入的型別參數的執行個體作為預設值。
1 from collections import defaultdict2 3 d_defaultdict = defaultdict(list)4 5 print(d_defaultdict)6 print(d_defaultdict.__getitem__('1'))7 print(d_defaultdict)
輸出如下:
1 defaultdict(<class 'list'>, {})2 []3 defaultdict(<class 'list'>, {'1': []})
由於初始化 defaultdict 時,傳入的類型是 list,因此 key 為 '1' 的 value 預設為 [],如果參數為 tuple,那麼 value 的預設值為 ()。
需要注意的是,預設值只有通過 defaultdict[key] 或 defaultdict.__getitem__(key) 訪問 defaultdict 時才會被初始化。
extend
問題來了 defaultdict 是如何?為不存在的 key 值初始化預設值的?
閱讀 _collections.py 源碼中的 class defaultdict(dict) 部分,可以看到一個 def __missing__(self, key) 的執行個體方法。
源碼如下:
1 def __missing__(self, key): # real signature unknown; restored from __doc__2 """3 __missing__(key) # Called by __getitem__ for missing key; pseudo-code:4 if self.default_factory is None: raise KeyError((key,))5 self[key] = value = self.default_factory()6 return value7 """8 pass
由此可見,當通過 __getitem__ 方法訪問 defaultdict 中的某個不存在的 key 值時,會在拋出的 KeyError 異常中進行處理,根據傳入的型別參數返回初始化的 value 值。
那麼,這個 __missing__ 方法中的內容可否自己實現呢,不妨試試:
1 class defaultdict_copy(dict): 2 def __missing__(self, key): 3 self[key] = 'default' 4 return 'default' 5 6 7 d_defaultdict_copy = defaultdict_copy() 8 print(d_defaultdict_copy) 9 print(d_defaultdict_copy['1'])10 print(d_defaultdict_copy)
輸出如下:
1 {}2 default3 {'1': 'default'}
很明顯,對於 dict 的繼承類中,存在一個 __missing__ 的執行個體方法,可以通過重寫該方法實現訪問不存在的 key 值時進行 value 的初始化。