collections.abc 模塊中有 Mapping 和 MutableMapping 這兩個抽象類,他們的做用是爲dict和其餘相似的類型定義形式接口。python
標準庫裏全部映射類型都是利用dict來實現的,所以他們有個共同的限制,只有可散列的數據類型才能用做這些映射裏的鍵。算法
可散列的數據類型:在這個對象的生命週期中,他的散列值是不變的,並且這個對象須要實現__hash__()方法,還要有__eq__()方法。數組
▲ 原子不可變數據類型(str、bytes和數值類型)、frozenset都是可散列類型。app
▲ 只有當一個元組包含的全部元素都是可散列類型的狀況下,它纔是可散列的。函數
字典提供了多種構造方法:spa
>>> a = dict(name='Li', sex='girl') >>> b = {'name':'Li', 'sex':'girl'} >>> c = dict(zip(['name','sex'], ['Li','girl'])) >>> d = dict([('name':'Li'), ('sex':'girl')]) >>> e = dict({'name':'Li', 'sex':'girl'}) >>> a == b == c == d == e True
2.一、字典推導code
從任何以鍵值對做爲元素的可迭代對象中構建出字典。對象
>>> DIAL_CODE = [ ... (86,'China'), ... (1,'United States'), ... ] >>> country_code = {country:code for code,country in DIAL_CODE} {'China': 86, 'United States': 1} >>> {country:code for country,code in country_code.items() if code > 50} {'China': 86}
2.二、用setdefault處理找不到的鍵blog
在不進行二次查找的狀況下更新列表繼承
my_dict.setdefault(key, []).append(new_value) # 等於 if key not in my_dict: my_dict[key] = [] my_dict[key].append(new_value)
某個鍵在映射中不存在時,咱們也但願經過這個鍵讀取值的時候能獲得一個默認值。
可使用defaultdict類型,或者自定義一個dict的子類,實現__missing__方法。
▲、在實例化一個defaultdict的時候,須要給構造方法提供一個可調用對象,這個可調用對象會在__getitem__找不到鍵的時候被調用,讓__getitem__返回某種默認值。
如:dd = defaultdict(list) , dd['new_key']
若是new_key在dd中不存在,表達式dd['new_key']會按以下步驟執行:
(1)、調用list() 創建一個新列表。
(2)、把這個新列表做爲值,‘new_key’做爲鍵,放到dd中。
(3)、返回這個列表的引用。
▲、這個用來生成默認值 list 的可調用對象存放在名爲 default_factory 的實例屬性裏。
▲、若是在建立defaultdict時沒有指定 default_factory ,查詢不存在鍵會觸發 keyError 。
▲、defaultdict 裏的 default_factory ,只會在__getitem__裏被調用(dd[k]),而dd.get(k)則會返回None。
特殊方法__missing__,只會被__getitem__調用。
提供__missing__方法對get或者__contains__(in 運算符會用到這個方法)這些方法的使用沒有影響。
collections.OrderedDict:添加鍵的時候後會保持順序
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2} >>> OrderedDict(sorted(d.items(), key=lambda t: t[0])) OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
collections.ChainMap:容納不一樣的映射對象,查找操做時,這些對象被看成一個總體被逐個查找。
collections.Counter:整數計數器。 元素被存儲爲字典鍵,它們的計數被存儲爲字典值。
collections.USerDict :讓用戶繼承寫子類。對一個字典對象的封裝。其實例的內容保存在一個普通的字典當中,能夠經過 UserDict 實例的屬性 data 訪問。
types模塊引入了一個封裝類名叫MappingProxyType。若是給這個類一個映射,它會返回一個只讀的映射視圖。
>>> from types import MappingProxyType >>> d = {'1':'one'} >>> d_proxy = MappingProxyType(d) >>> d_proxy mappingproxy({'1': 'one'}) >>> d_proxy['1'] 'one' >>> d_proxy['2'] = 'two' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'mappingproxy' object does not support item assignment >>> d['2'] = 'two' >>> d_proxy mappingproxy({'2': 'two', '1': 'one'})
集合的本質是許多惟一對象的彙集。因此,集合能夠用於去重。
集合中的元素必須是可散列的,set類型自己是不可散列的,可是forzenset能夠。因此能夠建立一個包含不一樣frozenset的set。
空集合:set()
集合一樣有屬於他的集合推導。
>>> from unicodedata import name >>> {chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')} {'\xa2', '\xac', '§', '±', '\xa9', '\xb5', '\xae', '°', '$', '\xa3', '=', '+', '¤', '%', '÷', '<', '\xa5', '\xb6', '>', '#', '×'}
散列表是一個稀疏數組(老是有空白元素的數組)。散列表裏的單元叫作表元。
在dict的散列表中,每個鍵值對都佔用一個表元,每一個表元都有兩個部分,一個是對鍵的引用,另外一個是對值得引用。
全部表元的大小一致,因此能夠經過偏移量來讀取某個表元。
Python會設法保證大概還有三分之一的表元是空的,在快要達到閾值的時候,原有的散列表會被複制到一個更大的空間裏面。
若是要把一個對象放入散列表,那麼首先要計算這個元素鍵的散列值。
內置的hash()方法用於全部內置對象,自定義對象調用hash()實際上運行自定義的__hash__。
若是兩個對象在比較時是相等的,那他們的散列值必須相等。如(1 == 1.0)
▲ 散列值在索引空間中儘可能分散開,越是類似的但不相等的對象,散列值的差異應該越大。如(1.0001和1.0002)
散列表算法:爲了獲取my_dict[search_key]的值
(1)首先調用hash(search_key)計算search_key的散列值,把這個值最低幾位數字當作偏移量,在散列表裏查找表元。
(2)若找到的表元是空的,拋出KeyError異常
(3)若不爲空,表元裏會有一對found_key:found_value。進行檢驗search_key == found_key是否爲真
(4)相等則返回found_value。不相等則稱爲散列衝突。
爲了解決散列衝突,算法會在散列值中另外再取幾位通過計算處理,把新獲得的數字再當作索引來尋找表元。
一個可散列對象必須知足如下條件:
(1)支持hash()函數,而且經過__hash__()方法獲得的散列值是不變的。
(2)經過__eq__()方法檢測相等性。
(3)若a == b爲真,則hash(a) == hash(b)也爲真。
全部由用戶自定義的對象默認都是可散列的。由於他們的散列值由id()來獲取,並且他們都不相等。
▲ 字典在內存中開銷巨大,典型的空間換時間。
▲ 鍵的次序取決於添加順序
▲ 往字典添加新鍵可能會改變已有鍵的順序(字典擴容決定)
set的實現:也依賴散列表,散列表裏存放的只有元素的引用