標準庫裏的全部映射類型都是利用 dict 來實現的
只有可散列的數據類型才能用做這些映射裏的鍵(值不用)python
DIAL_CODES = [(86, 'China'), (91, 'India'), (1, 'United States'), (62, 'Indonesia') ] country_code = {country: code for code, country in DIAL_CODES }
結果
{'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62}
##找對應的key,沒有的話返回默認值 my_dict = {"name":"longe","age":8} my_dict.setdefault("namerrr","default") print(my_dict)
用 setdefault 只須要一次就能夠完成整個操做。測試
原理
全部這一切背後的功臣實際上是特殊方法 __missing__。
它會在defaultdict 遇到找不到的鍵的時候調用 default_factory
自定義一個映射類型,更合適的策略實際上是繼承collections.UserDict 類spa
只是爲了演示 missing 是如何被dict.__getitem__ 調用的。code
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()
isinstance(key, str) 測試在上面的__missing__ 中是必需的
可是若是 str(k) 不是一個存在的鍵,代碼就會陷入無限遞歸。
這是由於 missing 的最後一行中的 self[str(key)] 會調用 __getitem__,
而這個 str(key) 又不存在,因而 __missing__又會被調用。對象
精簡版本blog
import collections class StrKeyDict(collections.UserDict): def __missing__(self, key): if isinstance(key, str): raise KeyError(key) return self[str(key)] def __contains__(self, key): return str(key) in self.data def __setitem__(self, key, item): self.data[str(key)] = item
setitem 會把全部的鍵都轉換成字符串。因爲把具體的實現委
託給了 self.data 屬性,這個方法寫起來也不難
這個類型在添加鍵的時候會保持順序,所以鍵的迭代次序老是一致
的。繼承
該類型能夠容納數個不一樣的映射對象,而後在進行鍵查找操做的時
候,這些對象會被看成一個總體被逐個查找,直到鍵被找到爲止。遞歸
這個映射類型會給鍵準備一個整數計數器。每次更新一個鍵的時候
都會增長這個計數器。ip
這個類其實就是把標準 dict 用純 Python 又實現了一遍。
跟 OrderedDict、ChainMap 和 Counter 這些開箱即用的類型不
同,UserDict 是讓用戶繼承寫子類的。下面就來試試。內存
from unicodedata import name aa = {chr(i) for i in range(32, 256) if 'SIGN' in name(chr(i), '')} print(aa)
到這個閾值的時候,原有的散列表會被複制到一個更大的空間裏面。
添加新元素和更新現有鍵值的操做幾乎跟上面同樣。
只不過對於前者,在發現空表元的時候會放入一個新元素;
對於後者,在找到相對應的表元后,原表裏的值對象會被替換成新值。
字典浪費存儲空間(不過沒有幾百萬對象,內存好幾個G不用考慮)
dict 的實現是典型的空間換時間:字典類型有着巨大的內存開銷
當往 dict 裏添加新鍵而又發生散列衝突的時候,新鍵可能會被安
排存放到另外一個位置。
容的決定。
能會跳過一些鍵——甚至是跳過那些字典中已經有的鍵。
update。
表),從而避免了重複的鍵搜索。