日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python进阶(第三章1) 字典

發(fā)布時(shí)間:2023/12/10 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python进阶(第三章1) 字典 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 3.1 泛映射類(lèi)型
        • 什么是可散列的數(shù)據(jù)類(lèi)型(鍵的要求)
        • 字典的構(gòu)造方法
    • 3.2 字典推導(dǎo)(dictcomp)
    • 3.3 常見(jiàn)的映射方法
        • 用setdefault處理找不到的鍵
    • 3.4 映射的彈性鍵查詢(xún)
      • 3.4.1 defaultdict:處理找不到的鍵的一個(gè)選擇
        • 注意:
        • defaultdict與dict實(shí)例化字典類(lèi)型的區(qū)別
        • defaultdict的構(gòu)造
      • 3.4.2 特殊方法__missing__
    • 3.5 字典的變種
        • collections.OrderedDict (添加鍵會(huì)保持順序)
        • collections.ChainMap(將多個(gè)映射合并為單個(gè)映射)
        • collections.Counter
          • 例子:統(tǒng)計(jì)單詞中各個(gè)字母出現(xiàn)的次數(shù)
        • collections.UserDict
    • 3.6 子類(lèi)化UserDict
      • MutableMapping.update
      • Mapping.get
        • 從dict或者其他內(nèi)置類(lèi)繼承有什么不好?
    • 3.7 不可變映射類(lèi)型(動(dòng)態(tài)的只讀的映射視圖:MappingProxyType)

3.1 泛映射類(lèi)型

collections.abc模塊有Mapping和MutableMapping 這兩個(gè)抽象基類(lèi),它們的作用是為了dict和其他類(lèi)似的類(lèi)型定義形式接口,然后非抽象映射類(lèi)型一般不會(huì)直接繼承這些抽象基類(lèi),它們會(huì)直接對(duì)dict或者collections.UserDict進(jìn)行擴(kuò)展。這些抽象基類(lèi)的主要作用是作為形式化的文檔,它們定義了構(gòu)建一個(gè)映射類(lèi)型所需要的最基本的接口。然后它們還可以跟isinstance一起被用來(lái)判定某個(gè)數(shù)據(jù)是不是廣義上的映射類(lèi)型:

>>> from collections import abc >>> my_dict={} # 字典是典型的鍵值對(duì) >>> isinstance(my_dict,abc.Mapping) True >>> isinstance([1, 2], abc.Mapping) False #列表時(shí)序列 >>> isinstance((1, 2), abc.Mapping) False #元組也是序列 >>> isinstance('sdbd', abc.Mapping) False #字符串也是序列
  • 這里用isintance而不是type來(lái)檢查某個(gè)參數(shù)是否為dict類(lèi)型,因?yàn)檫@個(gè)參數(shù)有可能不是dict,而是一個(gè)比較另類(lèi)的映射類(lèi)型。(這句話(huà)不太明白)
  • 標(biāo)準(zhǔn)庫(kù)里的所有映射類(lèi)型都是利用dict來(lái)實(shí)現(xiàn)的,因此它們有個(gè)共同的限制,即只有可散列的數(shù)據(jù)類(lèi)型才可以用作這些映射里的鍵(只有鍵有這個(gè)要求,值沒(méi)有此要求)

什么是可散列的數(shù)據(jù)類(lèi)型(鍵的要求)

如果一個(gè)對(duì)象是可散列的,那么在這個(gè)對(duì)象的生命周期中,它的散列值是不變的而且這個(gè)對(duì)象需要實(shí)現(xiàn)__hash__()方法。另外可散列對(duì)象還要有__eq__()方法,這樣才能和其他鍵作比較。如果兩個(gè)散列對(duì)象是相等的,那么它們的散列值一定是一樣
的。

可散列類(lèi)型包括:

  • (1)原子不可變類(lèi)型(str, bytes和數(shù)值類(lèi)型)
  • (2)frozenset
  • (3)元組:只有當(dāng)元組包含的所有元素都是可散列的情況下。
    可以用句話(huà)說(shuō):python里所有的不可變類(lèi)型都是可散列的
    一般來(lái)講用戶(hù)自定義的類(lèi)型的對(duì)象都是可散列的,散列值就是它們的id()函數(shù)的返回值。

字典的構(gòu)造方法

>>> a= dict(one=1,two=2,three=3) >>> b={'one':1,'two':2,'three':3} >>> c= dict(zip(['one','two','three'],[1,2,3])) >>> d = dict({'one':1,'two':2,'three':3}) >>> e=dict([('two',2),('one',1),('three',3)]) >>> a == b ==c == d == e True
  • 注意這里的相等,只不過(guò)是值相等,但是不同的對(duì)象

3.2 字典推導(dǎo)(dictcomp)

列表生成器和生成器表達(dá)式的概念已經(jīng)移植到了字典上,從而有了字典推導(dǎo)。
字典推導(dǎo)可以從任何鍵值對(duì)作為元素的可迭代對(duì)象中構(gòu)建出字典。
例子:

>>> DIAL_CODES=[ ... (86,'China'), ... (91,'India'), ... (1,'United States'), ... (62,'Indonesia'), ... (55,'Brazil'), ... (92,'Pakistan'), ... (880,'Bangladesh'), ... (234,'Nigeria'), ... (7,'Russia'), ... (81,'Japan'), ... ] >>> country_code={country:code for code,country in DIAL_CODES} >>> country_code {'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62, 'Brazil': 55, 'Pakistan': 92, 'Bangladesh': 880, 'Nigeria': 234, 'Russia': 7, 'Japan': 81} >>> {code:country.upper() for country,code in country_code.items() if code <66} {1: 'UNITED STATES', 62: 'INDONESIA', 55: 'BRAZIL', 7: 'RUSSIA'}

字典推導(dǎo)的表達(dá)式會(huì)蔓延到其他數(shù)據(jù)結(jié)構(gòu)類(lèi)型

3.3 常見(jiàn)的映射方法

除了

  • dict
  • defaultdict
  • OrderedDict

這三種常見(jiàn)方法
在映射對(duì)象的方法里,setdefault可能是比較微妙的一個(gè)。盡管用的次數(shù)不多,但是它一旦發(fā)揮作用,就可以節(jié)省不少次鍵查詢(xún),讓程序更高效。

用setdefault處理找不到的鍵

我們可以使用d.get(k,default)來(lái)代替d[k],給找不到的鍵一個(gè)默認(rèn)的返回值(這比處理keyError方便不少)
看個(gè)例子:

>>> my_dict = {'子': '鼠', '丑': '牛', '寅': '虎', ... '卯': '兔', '辰': '龍', '巳': '蛇', ... '午': '馬', '未': '羊', '申': '猴', ... '酉': '雞', '戌': '狗', '亥': '豬'} >>> my_dict.setdefault('子','屬鼠') # 顯然鍵 '子'存在,那么 值 '屬鼠' 也就無(wú)用 '鼠' >>> my_dict.setdefault('行初心','CSDN') # 如果找不到,就會(huì)添加. 'CSDN' >>> my_dict.setdefault('行') # 不存在的鍵"行",未指定值,默認(rèn)返回None >>> my_dict {'子': '鼠', '丑': '牛', '寅': '虎', '卯': '兔', '辰': '龍', '巳': '蛇', '午': '馬', '未': '羊', '申': '猴', '酉': '雞', '戌': '狗', '亥': '豬', '行初心': 'CSDN', '行': None}

例子2:(使用dict.setdefault()方法來(lái)設(shè)置默認(rèn)值,統(tǒng)計(jì)字符串出現(xiàn)的次數(shù))

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy') counts = {} for kw in strings:counts.setdefault(kw, 0)counts[kw] += 1

dict.setdefault()方法的返回值可以重寫(xiě)for循環(huán)中的代碼,使其更加簡(jiǎn)潔:

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy') counts = {} for kw in strings:counts[kw] = counts.setdefault(kw, 0) + 1

3.4 映射的彈性鍵查詢(xún)

為了方便,就算某個(gè)鍵在映射里不存在,那么你也希望在通過(guò)這個(gè)鍵讀取值的時(shí)候能得到一個(gè)默認(rèn)值。有兩個(gè)途徑幫我們達(dá)到這個(gè)目的。

  • (1).通過(guò)defaultdict這個(gè)類(lèi)型而不是普通的dict
  • (2).給自己定義一個(gè)dict類(lèi)型的子類(lèi),然后在這個(gè)子類(lèi)中實(shí)現(xiàn)__missing__方法。

3.4.1 defaultdict:處理找不到的鍵的一個(gè)選擇

在用戶(hù)創(chuàng)建defaultdict對(duì)象的時(shí)候,就需要給它配置一個(gè)為找不到的鍵創(chuàng)造默認(rèn)值的方法。
具體而言,在實(shí)例化一個(gè)defaultdict的時(shí)候,需要給構(gòu)造方法提供一個(gè)可調(diào)用的對(duì)象,這個(gè)可調(diào)用對(duì)象會(huì)在__getitem__碰到找不到的鍵的時(shí)候被調(diào)用,讓__getitem__返回某種默認(rèn)值。
比如,新建一個(gè)字典:dd=defaultdict(list),如果鍵’new-key’在dd中不存在的話(huà),表達(dá)式dd[‘new-key’]會(huì)按照以下步驟行事。

  • (1).調(diào)用list()來(lái)創(chuàng)建新列表
  • (2).把這個(gè)新列表作為值,'new-key’作為它的鍵,放到dd中。
  • (3).返回這個(gè)列表的引用
    而這個(gè)用來(lái)生成默認(rèn)值的可調(diào)用對(duì)象存放在名為default_factory的實(shí)例屬性里。
    如果在創(chuàng)建defaultdict的時(shí)候沒(méi)有指定default_factory,查詢(xún)不存在的鍵會(huì)觸發(fā)KeyError.

注意:

  • defaultdict里面的default_factory只會(huì)在__getitem__里被調(diào)用,在其他的方法里完全不會(huì)發(fā)揮作用。比如,dd是個(gè)defaultdict,K是個(gè)找不到的鍵,dd[k]這個(gè)表達(dá)式會(huì)調(diào)用default_factory創(chuàng)造某個(gè)默認(rèn)值,而dd.get(k)則會(huì)返回None.

所有 這一切背后的功臣其實(shí)是特殊方法__missing__.它會(huì)在defaultdict遇到找不到的鍵的時(shí)候調(diào)用default_factory,而實(shí)際上這個(gè)特性是所有映射類(lèi)型都可以去選擇的。

看個(gè)例子:

from collections import defaultdict class from_defaultdict(defaultdict):def __getitem__(self, key):return 'hello'c = from_defaultdict(list)print(c['new-key'])

結(jié)果如下:

defaultdict與dict實(shí)例化字典類(lèi)型的區(qū)別

使用defaultdict任何未定義的key都會(huì)默認(rèn)返回一個(gè)根據(jù)method_factory參數(shù)不同的默認(rèn)值, 而相同情況下dict()會(huì)返回KeyError.
比較下面代碼:

from collections import defaultdict d1 = dict() d2 = defaultdict(list) print(d2['a']) print(d1['a'])

輸出:

[] Traceback (most recent call last):File "/home/maxzhang/PycharmProjects/pythoncode/t.py", line 5, in <module>print(d1['a']) KeyError: 'a'

defaultdict的構(gòu)造

python官方文檔中對(duì)defaultdict的定義如下:

class collections.defaultdict([default_factory[, ...]])

python官方文檔中對(duì)defaultdict的解釋如下:

defaultdi: dict subclass that calls a factory function to supply missing values
  • default_factory 接收一個(gè)工廠(chǎng)函數(shù)作為參數(shù), 例如int str,list,set等.
  • defaultdict在dict的基礎(chǔ)上添加了一個(gè)__missing__(key)方法, 在調(diào)用一個(gè)不存的key的時(shí)候, defaultdict會(huì)調(diào)用__missing__, 返回一個(gè)根據(jù)default_factory參數(shù)的默認(rèn)值, 所以不會(huì)返回Keyerror.

3.4.2 特殊方法__missing__

所有的映射類(lèi)型在處理找不到的鍵的時(shí)候,都會(huì)牽扯到__missing__方法。這也是和這個(gè)方法稱(chēng)作’missing’的原因。雖然基類(lèi)dict并沒(méi)有定義這個(gè)方法,但是dict是知道有這么一個(gè)東西存在的。也就是說(shuō),如果有一個(gè)類(lèi)繼承了dict,然后這個(gè)繼承類(lèi)提供了__missing__方法,那么在__getitem__碰到找不到的鍵的時(shí)候,python會(huì)自動(dòng)調(diào)用它。而不是拋出異常。

  • 注意:__missing__方法只會(huì)被__getitem__調(diào)用。提供__missing__方法對(duì)get或者_(dá)_contains__這些方法的使用沒(méi)有影響。

如果要自定義一個(gè)映射類(lèi)型,更合適的策略是繼承collections.UserDict類(lèi)。

3.5 字典的變種

collections.OrderedDict (添加鍵會(huì)保持順序)

這個(gè)類(lèi)型在添加鍵的時(shí)候會(huì)保持順序,因此鍵的迭代次序總是一致的。OrderedDict的popitem方法默認(rèn)刪除并返回的是字典里的最后一個(gè)元素,但是如果像my_odict.popitem(last=False)這樣調(diào)用它,那么它刪除并返回第一個(gè)被添加進(jìn)去的元素。
例子:

>>> d = collections.OrderedDict() >>> d['a'] = 'A' >>> d['b'] = 'B' >>> d['c'] = 'C' >>> for k ,v in d.items(): ... print(k,v) ... a A b B c C >>> d.popitem(last=False) ('a', 'A') >>> d OrderedDict([('b', 'B'), ('c', 'C')])

collections.ChainMap(將多個(gè)映射合并為單個(gè)映射)

該類(lèi)型可以容納數(shù)個(gè)不同的映射對(duì)象,然后在進(jìn)行鍵查找操作的時(shí)候,這些對(duì)象會(huì)被當(dāng)做一個(gè)整體逐個(gè)查找,直到鍵被找到為止。
例子:

>>> import collections >>> a = {'x': 1, 'z': 3} >>> b = {'y': 2, 'z': 4} >>> c = collections.ChainMap(a, b) >>> c['x'] 1

collections.Counter

這個(gè)映射會(huì)給鍵準(zhǔn)備一個(gè)整數(shù)計(jì)數(shù)器。每次更新一個(gè)鍵的時(shí)候都會(huì)增加這個(gè)基數(shù)器。所以這個(gè)類(lèi)型可以用來(lái)給可散列表對(duì)象計(jì)數(shù),或者是當(dāng)成多重集來(lái)使用—多重集合就是集合里的元素可以出現(xiàn)不止一次。Counter實(shí)現(xiàn)了+和-運(yùn)算符用來(lái)合并記錄,還有像most_common([n])這類(lèi)很有用的方法。most_common([n])會(huì)按照次序返回映射里最常見(jiàn)的n個(gè)鍵和它們的計(jì)數(shù)。

例子:統(tǒng)計(jì)單詞中各個(gè)字母出現(xiàn)的次數(shù)
>>> ct = collections.Counter('afalfjlahgksdadaa') >>> ct Counter({'a': 6, 'f': 2, 'l': 2, 'd': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1}) >>> ct.update('aaaaaaaaadffdwe') >>> ct Counter({'a': 15, 'f': 4, 'd': 4, 'l': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1, 'w': 1, 'e': 1}) >>> ct.most_common(2) [('a', 15), ('f', 4)]

collections.UserDict

這個(gè)類(lèi)其實(shí)就是把標(biāo)準(zhǔn)dict用純python又實(shí)現(xiàn)了一遍
UserDict就是讓用戶(hù)繼承寫(xiě)子類(lèi)的。

3.6 子類(lèi)化UserDict

就創(chuàng)造自定義映射類(lèi)型來(lái)說(shuō),以UserDict為基類(lèi),總比以普通的dict為基類(lèi)要來(lái)的方便。
更傾向于從UserDict而不是從dict繼承的主要原因是,后者有時(shí)會(huì)在某些方法的實(shí)現(xiàn)上走一些捷徑,導(dǎo)致我們不得不在它的子類(lèi)中重寫(xiě)這些方法,但是UserDict就不會(huì)帶來(lái)這些問(wèn)題。
另外一個(gè)值得注意的地方是,UserDict并不是dict的子類(lèi),但是UserDict有一個(gè)叫做data的屬性是dict的實(shí)例,這個(gè)屬性就是UserDict最終存儲(chǔ)數(shù)據(jù)的地方。
例子:

import collectionsclass StrKeyDict(collections.UserDict):def __missing__(self, key):if isinstance(key,str):raise KeyErrorreturn self[str(key)]def __contains__(self, key):return str(key) in self.datadef __setitem__(self, key, item):self.data[str(key)] = item

因?yàn)閁serDict 繼承的是MutableMapping,所以StrKeyDict里剩下的的那些映射類(lèi)型的方法都是從UserDict,MutableMapping和Mapping這些超類(lèi)繼承而來(lái)的。特別是最后的Mapping類(lèi),它雖然是一個(gè)抽象類(lèi)(ABC),但是它提供了許多使用的方法。

MutableMapping.update

這個(gè)方法不但可以直接利用,它還用在__init__里,讓構(gòu)造方法可以利用傳入的各種參數(shù)(其他映射類(lèi)型,元素是(key,value)對(duì)的可迭代對(duì)象和鍵值參數(shù))來(lái)新建實(shí)例。因?yàn)檫@個(gè)方法在背后是使用self[key]=value來(lái)添加新值的,所以它其實(shí)是在使用我們的__setitem__方法

Mapping.get

從dict或者其他內(nèi)置類(lèi)繼承有什么不好?

3.7 不可變映射類(lèi)型(動(dòng)態(tài)的只讀的映射視圖:MappingProxyType)

標(biāo)準(zhǔn)庫(kù)里所有的映射類(lèi)型都是可變的,但是有時(shí)候你會(huì)有這樣的需求,比如不能讓用戶(hù)錯(cuò)誤修改某個(gè)映射。

在types模塊中引入了一個(gè)封裝類(lèi)名叫MappingProxyType。如果給這個(gè)類(lèi)一個(gè)映射,它會(huì)返回一個(gè)動(dòng)態(tài)的只讀的映射視圖。如果對(duì)原映射做出了修改,這個(gè)視圖可以觀(guān)察到,但是無(wú)法通過(guò)這個(gè)視圖對(duì)原映射進(jìn)行修改。
例子:

>>> from types import MappingProxyType >>> d = {1:'A'} >>> d_proxy = MappingProxyType(d) >>> d_proxy mappingproxy({1: 'A'}) >>> d_proxy[1] #d中的內(nèi)容可以通過(guò)d_proxy看到 'A' >>> d_proxy[2] = 'x' #但是d_proxy不能做任何的修改 Traceback (most recent call last):File "<stdin>", line 1, in <module> TypeError: 'mappingproxy' object does not support item assignment >>> d[2]= 'B' >>> d_proxy #d_proxy是動(dòng)態(tài)的,也就是說(shuō)對(duì)d所做的任何改動(dòng)都會(huì)反饋到它上面 mappingproxy({1: 'A', 2: 'B'}) >>> d_proxy[2] 'B' >>> 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的python进阶(第三章1) 字典的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。