Python使用collections模塊實(shí)現(xiàn)擴(kuò)展數(shù)據(jù)類
楔子
Python 標(biāo)準(zhǔn)庫提供了一個(gè) collections 模塊,里面提供了很多的數(shù)據(jù)類,在工作中使用這些類能夠簡化我們的開發(fā)。
下面就來看看這個(gè)模塊能夠幫助我們做哪些事情?
搜索多個(gè)字典
假設(shè)當(dāng)前有 3 個(gè)字典:dct1、dct2、dct3,現(xiàn)在要通過 key 查找對應(yīng)的 value。如果 key 在 dct1 里面存在,那么直接返回,否則從 dct2 里面找。dct2 里面如果不存在,那么從 dct3 里面找。
這個(gè)需求該怎么實(shí)現(xiàn)呢?
dct1?=?{"a":?1,?"b":?2,?"c":?3} dct2?=?{"d":?4,?"e":?5,?"f":?6} dct3?=?{"e":?7,?"f":?8,?"g":?9} def?get_value_by_key(key): ????if?key?in?dct1: ????????return?dct1[key] ????elif?key?in?dct2: ????????return?dct2[key] ????elif?key?in?dct3: ????????return?dct3[key] ????else: ????????raise?KeyError print(get_value_by_key("b"))??#?2 print(get_value_by_key("d"))??#?4 print(get_value_by_key("f"))??#?6
實(shí)現(xiàn)起來非常簡單,但通過 ChainMap 對象可以更方便地做到這一點(diǎn)。
from?collections?import?ChainMap dct1?=?{"a":?1,?"b":?2,?"c":?3} dct2?=?{"b":?4,?"c":?5,?"d":?6} #?將多個(gè)字典傳進(jìn)去, dct?=?ChainMap(dct1,?dct2) #?如果多個(gè)字典存在相同的?key,那么返回第一次出現(xiàn)的?key?對應(yīng)的?value print(dct["b"],?dct["d"]) """ 2?6 """ #?字典的?API?都可以使用 print(dct.items()) """ ItemsView(ChainMap({'a':?1,?'b':?2,?'c':?3},?{'b':?4,?'c':?5,?'d':?6})) """ #?也可以使用?get,如果?key?在所有的字典中都不存在 #?則返回默認(rèn)值 print(dct.get("k",?333)) """ 333 """ #?ChainMap?對象有一個(gè)?maps?屬性,存儲了要搜索的映射列表 #?這個(gè)列表是可變的,所以可以直接增加新映射,或者改變元素的順序以控制查找和更新行為。 print(dct.maps) """ [{'a':?1,?'b':?2,?'c':?3},?{'b':?4,?'c':?5,?'d':?6}] """ #?dct.maps?保存了原始的字典,修改?dct.maps?會影響原字典 print(dct1) """ {'a':?1,?'b':?2,?'c':?3} """ dct.maps[0]["a"]?=?11111111 print(dct1) """ {'a':?11111111,?'b':?2,?'c':?3} """ #?同理修改原字典,也會影響?dct.maps
以上就是 ChainMap 對象的用法,當(dāng)你需要從多個(gè)字典中進(jìn)行搜索的話,它會很有用。
統(tǒng)計(jì)可散列的對象
我們經(jīng)常會遇到數(shù)量統(tǒng)計(jì)相關(guān)的問題,比如有一個(gè)序列,計(jì)算里面每個(gè)元素出現(xiàn)了多少次。一般情況下,我們會這么做。
words?=?["hello",?"world", ?????????"hello",?"beautiful",?"world", ?????????"hello",?"cruel",?"world"] counter?=?{} for?word?in?words: ????if?word?in?counter: ????????counter[word]?+=?1 ????else: ????????counter[word]?=?1 print(counter) """ {'hello':?3,?'world':?3,?'beautiful':?1,?'cruel':?1} """
實(shí)現(xiàn)方法沒有任何問題,但通過 Counter 會更方便,并且還提供了更多功能。
from?collections?import?Counter words?=?["hello",?"world", ?????????"hello",?"beautiful",?"world", ?????????"hello",?"cruel",?"world"] #?將序列傳進(jìn)去即可 counter?=?Counter(words) print(counter) """ Counter({'hello':?3,?'world':?3,?'beautiful':?1,?'cruel':?1}) """ #?Counter?繼承?dict,所以字典的?API?它也是都支持的 counter?=?Counter(hello=3,?world=3,?beautiful=1,?cruel=1) print(counter) """ Counter({'hello':?3,?'world':?3,?'beautiful':?1,?'cruel':?1}) """
Counter 對象還支持動態(tài)更新操作,舉個(gè)例子:
from?collections?import?Counter #?Counter?需要接收一個(gè)可迭代對象,然后會遍歷它 #?所以結(jié)果就是?a?出現(xiàn)了三次,b?出現(xiàn)了兩次,c?出現(xiàn)了一次 counter?=?Counter("aaabbc") print(counter) """ Counter({'a':?3,?'b':?2,?'c':?1}) """ #?也可以動態(tài)更新,比如又來了一個(gè)序列 #?需要和當(dāng)前的?counter?組合起來進(jìn)行統(tǒng)計(jì) counter.update("bcd") print(counter) """ Counter({'a':?3,?'b':?3,?'c':?2,?'d':?1}) """ #?可以看到?b?和?c?的值都增加了?1,并且出現(xiàn)了?d #?需要注意的是:update 方法同樣接收一個(gè)可迭代對象,然后進(jìn)行遍歷 #?如果我希望添加一個(gè)?key?叫?"bcd"?的話,那么要這么做 counter.update(["bcd"]) print(counter) """ Counter({'a':?3,?'b':?3,?'c':?2,?'d':?1,?'bcd':?1}) """ #?訪問計(jì)數(shù),Counter?對象可以像字典一樣訪問 print(counter["a"])?? """ 3 """ #?如果訪問一個(gè)不存在的?key,不會引發(fā)?KeyError #?而是會返回?0,表示對象中沒有這個(gè)?key print(counter["mmp"])?? """ 0 """ #?還可以計(jì)算出現(xiàn)最多的元素,這是用的最頻繁的一個(gè)功能 #?統(tǒng)計(jì)?string?中前三個(gè)出現(xiàn)次數(shù)最多的元素 string?=?"sasaxzsdsadfscxzcasdscxzdfscxsasadszczxczxcsds" counter?=?Counter(string) print(counter) """ Counter({'s':?13,?'c':?7,?'a':?6,?'x':?6,?'z':?6,?'d':?6,?'f':?2}) """ print(counter.most_common(3)) """ [('s',?13),?('c',?7),?('a',?6)] """
Counter 對象還有一個(gè)強(qiáng)大的功能,就是它支持算數(shù)操作以及位運(yùn)算。
from?collections?import?Counter counter1?=?Counter("aabbccc") counter2?=?Counter("bbbccdd") print(counter1)?? print(counter2)?? """ Counter({'a':?2,?'b':?2,?'c':?3}) Counter({'b':?3,?'c':?2,?'d':?2}) """ #?如果?counter1?的元素出現(xiàn)在了?counter2?中 #?就把該元素減去,記住:減的是次數(shù) print(counter1?-?counter2)?? """ Counter({'a':?2,?'c':?1}) """ #?a?在?counter1?中出現(xiàn)了?2?次,在?counter2?中沒有出現(xiàn),所以是?a:?2 #?b?在?counter1?中出現(xiàn)了?2?次,在?counter2?中出現(xiàn)?3?次,所以一減就沒有了 #?c?在?counter1?中出現(xiàn)了?3?次,在?counter2?中出現(xiàn)?2?次,所以相減還剩下一次 #?至于?counter1?中沒有的元素就不用管了 #?相加就很好理解了 print(counter1?+?counter2)? """ Counter({'b':?5,?'c':?5,?'a':?2,?'d':?2})? """ #?相交的話,查找公共的元素,并且取次數(shù)出現(xiàn)較小的那個(gè) print(counter1?&?counter2)?? """ Counter({'b':?2,?'c':?2}) """ #?并集的話,取較大的,記住不是相加 #?所以?b?和?c?出現(xiàn)的次數(shù)不會增加,只是取較大的那個(gè) print(counter1?|?counter2)?? """ Counter({'b':?3,?'c':?3,?'a':?2,?'d':?2}) """
以上就是 Counter 的用法,更多的還是統(tǒng)計(jì)次數(shù),求 topK。
缺少的鍵返回默認(rèn)值
很明顯,這是針對于字典的。首先字典也支持這種操作,通過 setdefault 和 get 兩個(gè)方法,可以用來獲取 key 對應(yīng)的 value,并且還能在 key 不存在的時(shí)候給一個(gè)默認(rèn)值。
如果 key 存在,兩者會獲取 key 對應(yīng)的 value;但如果 key 不存在,setdefault 會先將 key 和指定的默認(rèn)值設(shè)置進(jìn)去,然后再將設(shè)置的值返回,而 get 則只會返回默認(rèn)值,不會進(jìn)行設(shè)置。
d?=?{"a":?1} #?如果?key?存在,直接返回?value print(d.get("a",?0))??#?1 print(d.setdefault("a",?0))??#?1 #?原字典不受影響 print(d)??#?{"a":?1} #?key?不存在,則返回指定的默認(rèn)值 print(d.get("b",?0))??#?0 #?原字典不受影響 print(d)??#?{"a":?1} #?key?不存在的話,會將?key?和默認(rèn)值組成鍵值對,設(shè)置在字典中 print(d.setdefault("b",?0))??#?0 print(d)??#?{"a":?1,?"b":?0}
指的一提的是,setdefault 是一個(gè)非常實(shí)用且簡潔的方法,但用的卻不多。我們舉一個(gè)例子:
data?=?[ ????("banana",?15),?("banana",?17),?("banana",?22), ????("apple",?31),?("apple",?30),?("apple",?33), ????("orange",?45),?("orange",?47),?("orange",?44), ] #?如果我希望將 data 轉(zhuǎn)成以下格式,該怎么辦呢? """ {'banana':?[15,?17,?22],? ?'apple':?[31,?30,?33],? ?'orange':?[45,?47,?44]} """ def?change_data1(): ????result?=?{} ????for?product,?count?in?data: ????????if?product?not?in?result: ????????????result[product]?=?[count] ????????else: ????????????result[product].append(count) ????return?result print(change_data1()) """ {'banana':?[15,?17,?22],? ?'apple':?[31,?30,?33],? ?'orange':?[45,?47,?44]} """ #?結(jié)果沒問題,但如果用?setdefault?的話會更方便 def?change_data2(): ????result?=?{} ????for?product,?count?in?data: ????????result.setdefault(product,?[]).append(count) ????return?result print(change_data2()) """ {'banana':?[15,?17,?22],? ?'apple':?[31,?30,?33],? ?'orange':?[45,?47,?44]} """
但這個(gè)功能也可以通過 defaultdict 完成,該類要求調(diào)用者傳遞一個(gè)類型,當(dāng) key 不存在時(shí)會返回對應(yīng)類型的零值。
from?collections?import?defaultdict d?=?defaultdict(int) print(d)??#?defaultdict(<class?'int'>,?{}) print(d["a"])??#?0 print(d)??#?defaultdict(<class?'int'>,?{'a':?0}) d?=?defaultdict(tuple) print(d)??#?defaultdict(<class?'tuple'>,?{}) print(d["a"])??#?() print(d)??#?defaultdict(<class?'tuple'>,?{'a':?()}) #?之前的例子就可以這么做 data?=?[ ????("banana",?15),?("banana",?17),?("banana",?22), ????("apple",?31),?("apple",?30),?("apple",?33), ????("orange",?45),?("orange",?47),?("orange",?44), ] result?=?defaultdict(list) for?product,?count?in?data: ????result[product].append(count) #?defaultdict?繼承?dict,支持字典的?API print(dict(result)) """ {'banana':?[15,?17,?22],? ?'apple':?[31,?30,?33],? ?'orange':?[45,?47,?44]} """ #?整個(gè)過程就是,key?如果存在,那么獲取?value #?key?不存在,那么將指定類型的零值作為?value(這里是空列表) #?并且返回之前,會先將?key、value?添加到鍵值對中 #?再比如之前的詞頻統(tǒng)計(jì) string?=?"aabbccdddddee" counter?=?defaultdict(int) for?c?in?string: ????counter[c]?+=?1 print(dict(counter)) """ {'a':?2,?'b':?2,?'c':?2,?'d':?5,?'e':?2} """
怎么樣,是不是很方便呢?在實(shí)例化 defaultdict 的時(shí)候,指定一個(gè)類型即可,獲取一個(gè)不存在的 key 的時(shí)候,會返回指定的類型的零值,并且還會將 key 和零值添加到字典中。
此外 defaultdict 還可以自定義返回值,只需要指定一個(gè)不需要參數(shù)的函數(shù)即可。
from?collections?import?defaultdict #?此時(shí)的默認(rèn)值就是?default d?=?defaultdict(lambda:?"default") print(d["aa"])??#?default #?此外還可以添加參數(shù),因?yàn)閱为?dú)指定了?aa,所以打印的時(shí)候以指定的為準(zhǔn) #?如果沒有指定,那么才會得到默認(rèn)值 d4?=?defaultdict(lambda:?"default",?aa="bar") print(d4["aa"])??#?bar print(d4["bb"])??#?default
那么估計(jì)會有人好奇,這是如何實(shí)現(xiàn)的呢?其實(shí)主要是實(shí)現(xiàn)了一個(gè)叫做 __missing__ 的魔法方法。字典在查找元素的時(shí)候,會調(diào)用 __getitem__,然后在找不到的時(shí)候會去調(diào)用 __missing__。但是注意:dict 這個(gè)類本身并沒有實(shí)現(xiàn) __missing__,所以我們需要繼承自 dict,然后在子類中實(shí)現(xiàn)。
class?MyDict(dict): ????def?__getitem__(self,?item): ????????#?執(zhí)行父類的?__getitem__?方法 ????????#?如果?key?不存在,會去執(zhí)行?__missing__?方法 ????????value?=?super().__getitem__(item) ????????#?所以這里的?value?就是?__missing__?方法的返回值 ????????return?value ????def?__missing__(self,?key): ????????self[key]?=?"搞事情?(′ー`?)搞事情" ????????return?self[key] d?=?MyDict([("a",?3),?("b",?4)]) print(d)??#?{'a':?3,?'b':?4} print(d["mmm"])??#?搞事情?(′ー`?)搞事情 print(d)??#?{'a':?3,?'b':?4,?'mmm':?'搞事情?(′ー`?)搞事情'}
都是一些基礎(chǔ)的內(nèi)容了,突然想到了,就提一遍。
雙端隊(duì)列
如果你需要維護(hù)一個(gè)序列,并根據(jù)需求動態(tài)地往序列的尾部添加元素和彈出元素,那么你會選擇什么序列呢?很明顯,如果只在尾部操作,那么列表一定是最合適的選擇。
但如果我們操作的不止是尾部,還有頭部呢?比如往序列的頭部添加和彈出元素,此時(shí)雙端隊(duì)列就是一個(gè)不錯(cuò)的選擇。
雙端隊(duì)列支持從任意一端添加和刪除元素,更為常用的兩種數(shù)據(jù)結(jié)構(gòu)(即棧和隊(duì)列)就是雙端隊(duì)列的退化形式,它們的輸入和輸出被限制在某一端。
from?collections?import?deque #?接收一個(gè)可迭代對象,然后進(jìn)行遍歷 d?=?deque("abcdefg") print(d)? """ deque(['a',?'b',?'c',?'d',?'e',?'f',?'g']) """ print(len(d))? """ 7 """ print(d[0])? """ a """ print(d[-1])?? """ g """ #?由于?deque?是一種序列容器,因此同樣支持?list?的操作 #?如:通過索引獲取元素,查看長度,刪除元素,反轉(zhuǎn)元素等等 #?list?支持的操作,deque?基本上都支持 d.reverse() print(d)??#?deque(['g',?'f',?'e',?'d',?'c',?'b',?'a']) d.remove("c") print(d)??#?deque(['g',?'f',?'e',?'d',?'b',?'a'])
deque 還有很多的 API,比如添加元素。
from?collections?import?deque d?=?deque("abc") #?添加元素,可以從兩端添加 d.append("Hello")??#?從尾部添加 d.appendleft("World")??#?也可以從頭部添加 print(d) """ deque(['World',?'a',?'b',?'c',?'Hello']) """ #?還可以使用?insert,?如果范圍越界,自動添加在兩端 d.insert(100,?"古明地覺") print(d) """ deque(['World',?'a',?'b',?'c',?'Hello',?'古明地覺']) """ #?也可以通過extend,extendleft?一次添加多個(gè)元素 d?=?deque([1,?2,?3]) d.extend([4,?5,?6]) print(d) """ deque([1,?2,?3,?4,?5,?6]) """ d.extendleft([7,?8,?9]) print(d) """ deque([9,?8,?7,?1,?2,?3,?4,?5,?6]) """ #?注意添加的順序,我們是從左邊開始添加的 #?先添加?7,然后?8?會跑到?7?的左邊,所以是結(jié)果是倒過來的
再來看看刪除元素:
from?collections?import?deque d?=?deque(range(1,?7)) print(d) """ deque([1,?2,?3,?4,?5,?6]) """ #?調(diào)用?pop?方法可以從尾部彈出一個(gè)元素 print(d.pop())??#?6 print(d.pop())??#?5 print(d.pop())??#?4 #?pop?是從右端刪除一個(gè)元素,popleft?是從左端開始刪除一個(gè)元素 #?但如果想?pop?掉指定索引的元素,則只能用?pop?函數(shù),傳入索引值即可 print(d.popleft())??#?1 print(d) """ deque([2,?3]) """ #?注意:deque 和 queue一樣,是線程安全的 #?它們均受?GIL?這把超級大鎖保護(hù),可以不同的線程中進(jìn)行消費(fèi) #?如果想清空里面的元素,可以像?list、dict?一樣,使用?clear?方法 d.clear() print(d)?? """ deque([]) """
最后 deque 還有一個(gè)非常有意思的方法,叫 rotate,它是做什么的呢?來看一下。
from?collections?import?deque #?按任意一個(gè)方向進(jìn)行旋轉(zhuǎn),從而跳過某些元素。 # d.rotate(n):n 大于0,從右邊開始取 n 個(gè)元素放到左邊 #?n?小于?0,從左邊取?n?個(gè)元素放到右邊 d?=?deque(range(10)) print(d)?? """ deque([0,?1,?2,?3,?4,?5,?6,?7,?8,?9]) """ #?從右邊取?2?個(gè)元素放到左邊,所以?8?和?9?被放到了左邊 d.rotate(2) print(d)?? """ deque([8,?9,?0,?1,?2,?3,?4,?5,?6,?7]) """ d.rotate(-3) #?從左邊取?3?個(gè)元素放到右邊,所以?8、9、0?被放到了右邊 print(d)?? """ deque([1,?2,?3,?4,?5,?6,?7,?8,?9,?0]) """
當(dāng)然雙端隊(duì)列默認(rèn)是容量無限的,但很多時(shí)候我們需要給隊(duì)列加上容量限制,如何加呢?
from?collections?import?deque #?限制隊(duì)列的大小 #?我們在初始化一個(gè)雙端隊(duì)列的時(shí)候,還可以限制它的大小 d?=?deque("abcdefg",?maxlen=5) #?我們初始化?7?個(gè)元素,但是指定最大長度只有?5 #?所以前面兩個(gè)元素("a"?和?"b")就被擠出去了 print(d) """ deque(['c',?'d',?'e',?'f',?'g'],?maxlen=5) """ #?當(dāng)我往前面添加元素的時(shí)候,后面的就被擠出去了 #?因?yàn)殛?duì)列最多只能容納?5?個(gè)元素 d.appendleft("Hello") print(d)?? """ deque(['Hello',?'c',?'d',?'e',?'f'],?maxlen=5) """
當(dāng)你要維護(hù)一個(gè)從首尾兩端添加、刪除元素的序列時(shí),使用 deque 是一個(gè)非常正確的選擇。
比如 asyncio 的鎖 Lock,當(dāng)獲取鎖時(shí),就會創(chuàng)建一個(gè) Future 對象,并保存在雙端隊(duì)列中。
帶有名字的元組
元組的話,我們都是通過索引來獲取元素,但通過索引的話,如果你不手動數(shù)一數(shù),你是不知道該索引會對應(yīng)哪一個(gè)元素的。所以問題來了,可不可以給里面的元素一個(gè)字段名呢?我們通過字段名來獲取對應(yīng)的值不就行啦,沒錯(cuò),這就是 namedtuple。
from?collections?import?namedtuple #?傳入名字,和字段 Person?=?namedtuple("Person",?["name",?"age",?"gender"]) person1?=?Person(name="satori",?age=16,?gender="f") print(person1) """ Person(name='satori',?age=16,?gender='f') """ print(person1.name,?person1.age,?person1.gender) """ satori?16?f """ print(person1[0]) """ satori """ #?不僅可以像普通的?tuple?一樣使用索引訪問 #?還可以像類一樣通過?.?字段名訪問 person2?=?Person("satori",?16,?"f") #?注意:這個(gè)和普通的元組一樣,是不可以修改的 try: ????person2.name?=?"xxx" except?AttributeError?as?e: ????print(e)??#?can't?set?attribute #?非法字段名,不能使用?Python?的關(guān)鍵字 try: ????namedtuple("keywords",?["for",?"in"]) except?ValueError?as?e: ????print(e) ????""" ????Type?names?and?field?names?cannot?be?a?keyword:?'for' ????""" #?如果字段名重復(fù)了,會報(bào)錯(cuò) try: ????namedtuple("Person",?["name",?"age",?"age"]) except?ValueError?as?e: ????print(e) ????""" ????Encountered?duplicate?field?name:?'age' ????""" #?如果非要加上重名字段,可以設(shè)置一個(gè)參數(shù) Person?=?namedtuple("Person",?["name",?"age",?"age"], ????????????????????rename=True) print(Person)?? """ <class?'__main__.Person'> """ person3?=?Person("koishi",?15,?15) #?可以看到重復(fù)的字段名會按照索引的值,在前面加上一個(gè)下劃線 #?比如第二個(gè)?age?重復(fù),它的索引是多少呢?是?2,所以默認(rèn)幫我們把字段名修改為?_2 print(person3)?? """ Person(name='koishi',?age=15,?_2=15) """ #?此外我們所有的字段名都保存在?_fields?屬性中 print(person3._fields)?? """ ('name',?'age',?'_2') """
但 namedtuple 還有一個(gè)不完美的地方,就是它無法指定字段的類型,所以我們更推薦使用 typing 模塊里的 NamedTuple。
from?typing?import?NamedTuple class?Person(NamedTuple): ????name:?str ????age:?int ????gender:?str p?=?Person("satori",?16,?"f") print(p) """ Person(name='satori',?age=16,?gender='f') """ #?同樣能夠基于索引和字段名來獲取值 print(p[0],?p.name) """ satori?satori """ #?創(chuàng)建類的話,還可以這么創(chuàng)建 Person?=?NamedTuple('Person',?name=str,?age=int,?gender=str) Person?=?NamedTuple( ????'Person',?[("name",?str),?("age",?int),?("gender",?str)] )
更建議使用 NamedTuple。
記住鍵值對順序的字典
從 Python3.6 開始,字典遍歷默認(rèn)是有序的,但我們不應(yīng)該依賴這個(gè)特性。如果希望字典有序,應(yīng)該使用 OrderDict 字典子類。
from?collections?import?OrderedDict d?=?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 """ #?此外也可以在初始化的時(shí)候,添加元素 print(OrderedDict({"a":?1}))?? """ OrderedDict([('a',?1)]) """ #?相等性,對于常規(guī)字典來說,只要里面元素一樣便是相等的,不考慮順序 #?但是對于OrderDict來說,除了元素,順序也要一樣,否則就不相等 d1?=?{"a":?1,?"b":?2} d2?=?{"b":?2,?"a":?1} print(d1?==?d2)?? """ True """ d1?=?OrderedDict({"a":?1,?"b":?2}) d2?=?OrderedDict({"b":?2,?"a":?1}) print(d1?==?d2)?? """ False """ #?重排,在?OrderDict?中可以使用?move_to_end?方法 #?將某個(gè)鍵移動到序列的起始位置或末尾位置來改變順序 d3?=?OrderedDict({"a":?1,?"b":?2,?"c":?3,?"d":?4}) #?表示將?key="c"?的鍵值對移動到末尾 d3.move_to_end("c")?? print(d3)?? """ OrderedDict([('a',?1),?('b',?2),?('d',?4),?('c',?3)]) """ #?表示將?key="c"?的這個(gè)鍵值對移動到行首 d3.move_to_end("c",?last=False)?? print(d3)?? """ OrderedDict([('c',?3),?('a',?1),?('b',?2),?('d',?4)]) """ #?從尾部彈出一個(gè)元素 print(d3.popitem()) """ ('d',?4) """ #?從頭部彈出一個(gè)元素 print(d3.popitem(last=False)) """ ('c',?3) """
使用 OrderDict 要比 dict 更加耗費(fèi)內(nèi)存,因此在存儲大量鍵值對的時(shí)候,思考一下,是否需要保證鍵值對有序。
但在實(shí)現(xiàn) LRU 緩存的時(shí)候,OrderDict 非常常用,比如某個(gè)鍵被訪問了,通過 move_to_end 移到頭部。當(dāng)緩存滿了的時(shí)候,通過 popitem 彈出尾部元素。
以上就是Python使用collections模塊實(shí)現(xiàn)擴(kuò)展數(shù)據(jù)類的詳細(xì)內(nèi)容,更多關(guān)于Python collections的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python Dask庫處理大規(guī)模數(shù)據(jù)集的強(qiáng)大功能實(shí)戰(zhàn)
Dask是一個(gè)靈活、開源的Python庫,專為處理大規(guī)模數(shù)據(jù)集而設(shè)計(jì),與傳統(tǒng)的單機(jī)計(jì)算相比,Dask能夠在分布式系統(tǒng)上運(yùn)行,有效利用集群的計(jì)算資源,本文將深入介紹Dask的核心概念、功能和實(shí)際應(yīng)用,通過豐富的示例代碼展示其在大數(shù)據(jù)處理領(lǐng)域的強(qiáng)大能力2023-12-12關(guān)于Pytorch MaxUnpool2d中size操作方式
今天小編就為大家分享一篇關(guān)于Pytorch MaxUnpool2d中size操作方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01python實(shí)現(xiàn)簡易五子棋游戲(控制臺版)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡易五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Python內(nèi)置函數(shù)——__import__ 的使用方法
本篇文章主要介紹了Python內(nèi)置函數(shù)——__import__ 的使用方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11如何使用matplotlib讓你的數(shù)據(jù)更加生動
數(shù)據(jù)可視化用于以更直接的表示方式顯示數(shù)據(jù),并且更易于理解,下面這篇文章主要給大家介紹了關(guān)于如何使用matplotlib讓你的數(shù)據(jù)更加生動的相關(guān)資料,需要的朋友可以參考下2021-11-11Python機(jī)器學(xué)習(xí)NLP自然語言處理基本操作之命名實(shí)例提取
自然語言處理(?Natural?Language?Processing,?NLP)是計(jì)算機(jī)科學(xué)領(lǐng)域與人工智能領(lǐng)域中的一個(gè)重要方向。它研究能實(shí)現(xiàn)人與計(jì)算機(jī)之間用自然語言進(jìn)行有效通信的各種理論和方法2021-11-11Python創(chuàng)建文件和追加文件內(nèi)容實(shí)例
這篇文章主要介紹了Python創(chuàng)建文件和追加文件內(nèi)容實(shí)例,本文同時(shí)給出了把標(biāo)準(zhǔn)輸出定向到文件實(shí)例,需要的朋友可以參考下2014-10-10