python字典和集合对象可以进行索引操作_Python中的字典跟集合整理笔记
泛映射類型
映射類型:不僅僅是dict,標(biāo)準(zhǔn)庫里的所有映射類型都是利用dict來實(shí)現(xiàn)的,因此它們有個(gè)共同的限制,即只有可散列的數(shù)據(jù)類型才能用做這些映射的鍵。(只有鍵有這個(gè)需求,值并不需要必須是可散列的數(shù)據(jù)類型。)
什么是可散列的數(shù)據(jù)類型?
可散列的對(duì)象在它的生命周期中,散列值是不變的,需要實(shí)現(xiàn)__hash__()方法。另外散列對(duì)象還要有__eq__()方法,這樣才能跟其他鍵作比較。 - 原子不可變數(shù)據(jù)類型都是可散列的(str,bytes和數(shù)值類型,frozenset) -?dict,list是不可散列的
用setdefault處理找不到的鍵
當(dāng)字典d[k]找不到值會(huì)拋出異常,通常我們使用d.get(k,default)來代替d[k],給找不到的鍵默認(rèn)一個(gè)返回值。 但是要更新某個(gè)鍵對(duì)應(yīng)的值的時(shí)候,不管是用__getitem__還是get都不太自然的,效率很低。
# 這樣使用 setdefaultmy_dict.setdefault(key,[]).append(new_value)# 跟這樣寫使用默認(rèn)的dictif key not in my_dict:
my_dict[key]=[]my_dict[key].append(new_value)
兩者的效果是一樣的,只不過后者至少要進(jìn)行兩次查詢——如果鍵不存在的話,就是三次,使用setdefault只需要一次就可以完成整個(gè)操作。
映射的彈性查詢
所謂的彈性查詢就是,我找的鍵不在映射里面存在的時(shí)候,也能返回一個(gè)默認(rèn)值比如
d.get(key,default)
python有兩個(gè)途徑達(dá)到整個(gè)目的, - 一個(gè)是通過defaultdict這個(gè)類型而不是普通的dict?- 另一個(gè)是給自己頂一個(gè)dict的子類,然后在子類中實(shí)現(xiàn)__missing__方法。
defaultdict:處理找不到的鍵的一個(gè)選擇
dd = defaultdict(list) print(dd['new-key']) # []"""調(diào)用list()來建立一個(gè)列表。把這個(gè)新列表作為值,'new-key'作為它的鍵,放到dd中。返回這個(gè)列表的引用。"""print(dd) #defaultdict(, {'dddd': []})
注意如果在創(chuàng)建defaultdict的時(shí)候沒有指定default_factory,查詢不存在鍵會(huì)觸發(fā)KeyError
特殊方法__missing__
所有的映射類型找不到鍵的時(shí)候,都會(huì)使用到__missing__方法。 雖然基類dict并沒有定義這個(gè)方法,但是dict知道有這么個(gè)東西的存在。 也就是說,如果有一個(gè)類繼承了dict,然后這個(gè)繼承類提供了__missing__方法, 那么在__getitem__碰到找不到鍵的時(shí)候,python會(huì)自動(dòng)調(diào)用它,而不是拋出一個(gè)KeyError異常。?__missing__方法只會(huì)被__getitem__調(diào)用
字典的變種
collections.OrderedDict:這個(gè)類型在添加鍵的時(shí)候會(huì)保持順序,因此鍵的迭代次序總是一致的。
collections.ChainMap:該類型可以容納數(shù)個(gè)不同的對(duì)象,然后在進(jìn)行鍵查找操作的時(shí)候,這些對(duì)象會(huì)被當(dāng)做一個(gè)整體逐個(gè)被查找。
import collections# 初始化字典dict1 = {'a': 1, 'b': 2}dict2 = {'b': 3, 'c': 4}# 初始化ChainMapchain = collections.ChainMap(dict1, dict2)# 使用maps輸出chainMapprint(chain.maps) ?# [{'b': 2, 'a': 1}, {'b': 3, 'c': 4}]# 輸出keyprint(list(chain.keys())) ?# ['b', 'c', 'a']# 輸出值print(list(chain.values())) ?# [2, 4, 1]# 訪問print(chain['b']) ?# 2print(chain.get('b')) ?# 2# 使用new_child添加新字典dict3 = {'f': 5}new_chain = chain.new_child(dict3)print(new_chain.maps) ?# [{'f': 5}, {'b': 2, 'a': 1}, {'b': 3, 'c': 4}]reversed(new_chain.maps)print(new_chain.maps)
collections.Counter:這個(gè)映射類型會(huì)給鍵準(zhǔn)備一個(gè)整數(shù)計(jì)數(shù)器。每次更新一個(gè)鍵的時(shí)候都會(huì)增加這個(gè)計(jì)數(shù)器。
collections.UserDict:把標(biāo)準(zhǔn)的dict用純python又實(shí)現(xiàn)了一遍。
不可變的映射類型
標(biāo)準(zhǔn)庫里所有的映射類型都是可變的,如果遇到不能讓用戶錯(cuò)誤的修改某個(gè)映射。 使用types.MappingProxyType,如果給這個(gè)類一個(gè)映射,它會(huì)返回一個(gè)只讀的映射視圖(動(dòng)態(tài)的)。
集合
相對(duì)dict,set這個(gè)概念在python算是比較年輕的,有set 跟 frozenset?集合的本質(zhì)是許多唯一對(duì)象的聚集,所以集合中的元素必須都是可散列的,set類型本身是不可散列的,但是frozenset時(shí)可散列的。 集合可以進(jìn)行中綴運(yùn)算符。
dict和set的背后python里的dict和set的效率有多高?
為什么它們是無序的?
為什么并不是所有的python對(duì)象都可以當(dāng)做dict的鍵或者是set的元素?
為什么dict的鍵和set元素的順序是根據(jù)他們被添加的次序而定的,以及為什么在映射對(duì)象的生命周期中,這個(gè)順序是一成不變的?
為什么不應(yīng)該在迭代循環(huán)dict或者是set的同時(shí)往里添加元素?
字典中的散列表
散列表其實(shí)是一個(gè)稀疏數(shù)組(總是有空白元素的數(shù)組成為稀疏數(shù)組)?散列表里的單元通常叫做表元(bucket),在dict的散列表中每個(gè)鍵值對(duì)都占用一個(gè)表元,每個(gè)表元分都有兩個(gè)部分,一個(gè)是對(duì)鍵的引用,一個(gè)是對(duì)值的引用。 如果把對(duì)象放到散列表,那么首先要計(jì)算這個(gè)元素鍵的散列值,python中可以用hash()方法來做這個(gè)事情。
散列值和相等性
如果1==1.0為真,那么`hash(1)==hash(1.0)也必須為真
散列表算法
為了獲取my_dict[search_key]背后的值,Python首先調(diào)用hash(search_key)來計(jì)算search_key的散列值,把這個(gè)值最低的幾位數(shù)字當(dāng)做偏移量,在散列表里查找表元(具體取幾位,得看當(dāng)前散列表的大小)。 若找到的表元為空的,則拋出KeyError異常。若不為空的,則表元里會(huì)有一對(duì)found_key:found_value。 這時(shí)候python會(huì)檢驗(yàn)search_key == found_key是否為真,如果它們相等,就回返回found_value。 如果search_key和found_key不匹配的話,這種情況稱為散列沖突。 發(fā)生原因是散列表所做的其實(shí)是把隨機(jī)的元素映射到只有幾位的數(shù)字上,而散列表本身的索引又只依賴于這個(gè)數(shù)字的一部分。 為了解決散列沖突,算法會(huì)在散列值中另外再取幾位,然后用特殊方法處理一下,把新的到的數(shù)據(jù)在當(dāng)做索引來尋找表元。
問題:如果定位一個(gè)表元?[^2]
dict的實(shí)現(xiàn)及其導(dǎo)致的結(jié)果
散列表帶給dict的優(yōu)勢(shì)和限制。
鍵必須是可散列的
一個(gè)可散列的對(duì)象必須滿足以下的需求: - 支持hash()函數(shù),并且通過__hash__()方法所得到的散列值是不變的。 - 支持通過__eq__()方法來檢測(cè)相等性。 - 若?a == b為真,則hash(a) == hash(b)也為真。
用戶自定義的對(duì)象默認(rèn)是可散列的,它們的散列值有id()來獲取。
字典在內(nèi)存上面開銷巨大
通常不需要優(yōu)化,如果數(shù)據(jù)量巨大考慮使用tuple()來替代dict()
特殊方法__slots__
鍵查詢很快
dict的實(shí)現(xiàn)是典型的空間換時(shí)間
鍵的次序取決于添加順序
當(dāng)往dict中添加新建而又發(fā)生散列沖突的時(shí)候,新建可能會(huì)被安排存放在另個(gè)一個(gè)位置。
dict([key1,value1],[key2,value2]) == dict([key2,value2],[key1,value1]) # true
雖然鍵的次序是亂的,但是被視作相等的。這就是為什么說字典是無序的原因。
往字典中添加新建可能會(huì)改變已有鍵的順序
無論何時(shí)往字典添加新的鍵,Python的解釋器都可能做出為字典擴(kuò)容的決定。 擴(kuò)容導(dǎo)致的結(jié)果是需要一個(gè)更大散列表,并把字典里已有的元素添加到新表里,這個(gè)過程就可能出現(xiàn)散列沖突,導(dǎo)致新的散列表中的鍵的次序變化。
所以不要對(duì)字典同時(shí)迭代和修改。?python3中的.keys() .items() 和.values()方法返回都是字典的視圖,這些方法返回的值更像是集合。
set的實(shí)現(xiàn)以及導(dǎo)致的結(jié)果可以參照沒有值dict
總結(jié)
以上是生活随笔為你收集整理的python字典和集合对象可以进行索引操作_Python中的字典跟集合整理笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中北大学计算机二级负责老师,导师信息#中
- 下一篇: python对象的三个属性_Python