摘要:小總結(jié)標(biāo)準(zhǔn)庫里的所有映射類型都是利用來實現(xiàn)只有可散列的數(shù)據(jù)類型才能用作這些映射里的鍵值不用字典推導(dǎo)用處理找不到的鍵找不到鍵返回某種默認值底層是與調(diào)用實現(xiàn)的字典插入更新原理其他大多數(shù)映射類型都提供了兩個很強大的方法和。
字典和集合
標(biāo)準(zhǔn)庫里的所有映射類型都是利用 dict 來實現(xiàn)的
只有可散列的數(shù)據(jù)類型才能用作這些映射里的鍵(值不用)
一個對象是可散列的
它的散列值是不變的
對象需要實現(xiàn) __hash__() 方法
可散列對象還要有 __qe__() 方法
字典推導(dǎo)DIAL_CODES = [(86, "China"), (91, "India"), (1, "United States"), (62, "Indonesia") ] country_code = {country: code for code, country in DIAL_CODES }
結(jié)果常見的映射方法 page137 用setdefault處理找不到的鍵
{"China": 86, "India": 91, "United States": 1, "Indonesia": 62}
##找對應(yīng)的key,沒有的話返回默認值 my_dict = {"name":"longe","age":8} my_dict.setdefault("namerrr","default") print(my_dict)
用 setdefault 只需要一次就可以完成整個操作。
defaultdict找不到鍵返回某種默認值在實例化一個 defaultdict 的時候
這個可調(diào)用對象會在 getitem 碰到找不到的鍵的時候被調(diào)用,
讓 getitem 返回某種默認值。
實現(xiàn)方式defaultdict 里的 default_factory 只會在__getitem__ 里被調(diào)用
dd[k] 這個表達式會調(diào)用 default_factory 創(chuàng)造某個默認值,
dd.get(k) 則會返回 None。
原理__missing__這個方法
所有這一切背后的功臣其實是特殊方法 __missing__。
它會在defaultdict 遇到找不到的鍵的時候調(diào)用 default_factory
自定義一個映射類型,更合適的策略其實是繼承collections.UserDict 類
只是為了演示 missing 是如何被dict.__getitem__ 調(diào)用的。
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)] 會調(diào)用 __getitem__,
而這個 str(key) 又不存在,于是 __missing__又會被調(diào)用。
精簡版本
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 會把所有的鍵都轉(zhuǎn)換成字符串。由于把具體的實現(xiàn)委字典的變種
托給了 self.data 屬性,這個方法寫起來也不難
這個類型在添加鍵的時候會保持順序,因此鍵的迭代次序總是一致
的。
該類型可以容納數(shù)個不同的映射對象,然后在進行鍵查找操作的時
候,這些對象會被當(dāng)作一個整體被逐個查找,直到鍵被找到為止。
這個映射類型會給鍵準(zhǔn)備一個整數(shù)計數(shù)器。每次更新一個鍵的時候
都會增加這個計數(shù)器。
這個類其實就是把標(biāo)準(zhǔn) dict 用純 Python 又實現(xiàn)了一遍。
跟 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)集合的數(shù)學(xué)運算 page161 字典空間
因為 Python 會設(shè)法保證大概還有三分之一的表元是空的,所以在快要達
到這個閾值的時候,原有的散列表會被復(fù)制到一個更大的空間里面。
散列表原理為了獲取 my_dict[search_key] 背后的值
Python 首先會調(diào)用hash(search_key) 來計算 search_key 的散列值,
把這個值最低的幾位數(shù)字當(dāng)作偏移量
在散列表里查找表元(具體取幾位,得看當(dāng)前散列表的大小
若找到的表元是空的,則拋出 KeyError 異常。
若不是空的,則表元里會有一對 found_key:found_value。
這時候 Python 會檢驗 search_key == found_key 是否為真,如 果它們相等的話,就會返回found_value。
如果 search_key 和 found_key 不匹配的話,這種情況稱為散列 沖突。
原理圖 添加新元素和更新現(xiàn)有鍵值添加新元素和更新現(xiàn)有鍵值的操作幾乎跟上面一樣。
只不過對于前者,在發(fā)現(xiàn)空表元的時候會放入一個新元素;
對于后者,在找到相對應(yīng)的表元后,原表里的值對象會被替換成新值。
字典浪費存儲空間(不過沒有幾百萬對象,內(nèi)存好幾個G不用考慮)
dict 的實現(xiàn)是典型的空間換時間:字典類型有著巨大的內(nèi)存開銷
當(dāng)往 dict 里添加新鍵而又發(fā)生散列沖突的時候,新鍵可能會被安
排存放到另一個位置。
無論何時往字典里添加新的鍵,Python 解釋器都可能做出為字典擴
容的決定。
擴容導(dǎo)致的結(jié)果就是要新建一個更大的散列表,并把字典里已有的元素添加到新表里。
這個過程中可能會發(fā)生新的散列沖突,導(dǎo)致新散列表中鍵的次序變化。
要注意的是,上面提到的這些變化是否會發(fā)生以及如何發(fā)生,都依賴于字典背后的具體實現(xiàn),
因此你不能很自信地說自己知道背后發(fā)生了什么。
如果你在迭代一個字典的所有鍵的過程中同時對字典進行修改,那么這個循環(huán)很有可
能會跳過一些鍵——甚至是跳過那些字典中已經(jīng)有的鍵。
更新字典的主要使用姿勢由此可知,不要對字典同時進行迭代和修改。
如果想掃描并修改一個字典,最好分成兩步來進行:
首先對字典迭代,以得出需要添加的內(nèi)容,把這些內(nèi)容放在一個新字典里;
迭代結(jié)束之后再對原有字典進行更新。
小總結(jié):標(biāo)準(zhǔn)庫里的所有映射類型都是利用 dict 來實現(xiàn)
只有可散列的數(shù)據(jù)類型才能用作這些映射里的鍵(值不用)
字典推導(dǎo)
用setdefault處理找不到的鍵
defaultdict找不到鍵返回某種默認值
底層是 getitem 與__miss__調(diào)用實現(xiàn)的
字典插入更新原理!!!
其他大多數(shù)映射類型都提供了兩個很強大的方法:setdefault 和
update。
setdefault 方法可以用來更新字典里存放的可變值(比如列
表),從而避免了重復(fù)的鍵搜索。
update 方法則讓批量更新成為可能,它可以用來插入新值或者更新已有鍵值對,它的參數(shù)可以是包含(key, value) 這種鍵值對的可迭代對象,或者關(guān)鍵字參數(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/41625.html
摘要:第一章數(shù)據(jù)類型隱式方法利用快速生成字典方法方法通過下標(biāo)找元素自動支持切片操作可迭代方法與如果是一個自定義類的對象,那么會自己去調(diào)用其中由你實現(xiàn)的方法。若返回,則會返回否則返回。一個對象沒有函數(shù),解釋器會用作為替代。 第一章 python數(shù)據(jù)類型 1 隱式方法 利用collections.namedtuple 快速生成字典 import collections Card = coll...
摘要:第一章數(shù)據(jù)類型隱式方法利用快速生成類方法方法通過下標(biāo)找元素自動支持切片操作可迭代方法與如果是一個自定義類的對象,那么會自己去調(diào)用其中由你實現(xiàn)的方法。若返回,則會返回否則返回。一個對象沒有函數(shù),解釋器會用作為替代。 第一章 python數(shù)據(jù)類型 1 隱式方法 利用collections.namedtuple 快速生成類 import collections Card = collec...
摘要:可以通過定位參數(shù)和關(guān)鍵字參數(shù)傳入的形參多數(shù)函數(shù)的參數(shù)屬于此類。就像數(shù)據(jù)格式化一樣數(shù)據(jù)帶上標(biāo)簽自行創(chuàng)建函數(shù)它會自行創(chuàng)建函數(shù)。創(chuàng)建的函數(shù)會在對象上調(diào)用參數(shù)指定的方法自己創(chuàng)建函數(shù)凍結(jié)參數(shù)這個高階函數(shù)用于部分應(yīng)用一個函數(shù)。 高階函數(shù) 接受函數(shù)為參數(shù),或者把函數(shù)作為結(jié)果返回的函數(shù)是高階函數(shù) def reverse(word): return word[::-1] ...
摘要:把具名元組以的形式返回,我們可以利用它來把元組里的信息友好地呈現(xiàn)出來。數(shù)組支持所有跟可變序列有關(guān)的操作,包括和。雙向隊列和其他形式的隊列類雙向隊列是一個線程安全可以快速從兩端添加或者刪除元素的數(shù)據(jù)類型。 列表表達式 >>> symbols = $¢£¥€¤ >>> codes = [ord(symbol) for symbol in symbols] >>> codes [36, 16...
摘要:函數(shù)裝飾器和閉包嚴(yán)格來說,裝飾器只是語法糖。何時執(zhí)行裝飾器它們在被裝飾的函數(shù)定義之后立即運行。裝飾器突出了被裝飾的函數(shù)的作用,還便于臨時禁用某個促銷策略只需把裝飾器注釋掉。 函數(shù)裝飾器和閉包 嚴(yán)格來說,裝飾器只是語法糖。如前所示,裝飾器可以像常規(guī)的可調(diào)用對象那樣調(diào)用,其參數(shù)是另一個函數(shù)。有時,這樣做更方便,尤其是做元編程(在運行時改變程序的行為)時。 Python何時執(zhí)行裝飾器 它們在...
閱讀 3093·2023-04-26 02:27
閱讀 2801·2021-11-22 13:54
閱讀 936·2021-11-12 10:36
閱讀 3795·2021-10-09 09:44
閱讀 3206·2021-10-09 09:41
閱讀 1265·2021-09-22 10:02
閱讀 2880·2019-08-30 15:56
閱讀 3136·2019-08-30 11:02