Python 中的 OrderedDict 與 dict:適合工作的正確工具(Python是什么意思)

      網(wǎng)友投稿 1163 2025-04-01

      目錄


      在 OrderedDict 和 dict 之間進行選擇

      Python 的 OrderedDict 入門

      創(chuàng)建 OrderedDict 對象

      管理 OrderedDict 中的項目

      迭代 OrderedDict

      使用 reversed() 以相反的順序迭代

      探索 Python 的 OrderedDict 的獨特功能

      使用 .move_to_end() 重新排序項目

      使用 .popitem() 刪除項目

      測試字典之間的相等性

      將新屬性附加到字典實例

      使用運算符合并和更新字典

      考慮性能

      為工作選擇合適的詞典

      構建基于字典的隊列

      結論

      有時您需要一個 Python字典來記住其項目的順序。過去,您只有一種工具可以解決這個特定問題:Python 的OrderedDict.?它是一個字典子類,專門用于記住項的順序,由鍵的插入順序定義。

      這在 Python 3.6 中發(fā)生了變化。內(nèi)置dict類現(xiàn)在也保持其項目的有序性。因此,Python 社區(qū)中的許多人現(xiàn)在想知道它OrderedDict是否仍然有用。仔細觀察OrderedDict會發(fā)現(xiàn)這個類仍然提供有價值的特性。

      在本教程中,您將學習如何:

      在代碼中創(chuàng)建和使用OrderedDict對象

      找出差異之間OrderedDict和dict

      了解優(yōu)點和缺點使用OrderedDictVSdict

      有了這些知識,當您想要保留項目的順序時,您將能夠選擇最適合您需要的字典類。

      在本教程結束時,您將看到一個使用 實現(xiàn)基于字典的隊列的示例,OrderedDict如果您使用常規(guī)dict對象,這將更具挑戰(zhàn)性。

      在OrderedDict和之間選擇dict

      多年來,Python字典都是無序的數(shù)據(jù)結構。Python 開發(fā)人員已經(jīng)習慣了這個事實,當他們需要保持數(shù)據(jù)有序時,他們依賴于列表或其他序列。隨著時間的推移,開發(fā)人員發(fā)現(xiàn)需要一種新型字典,可以保持其項目有序。

      早在 2008 年,PEP 372 就引入了向collections.?它的主要目標是記住由插入鍵的順序定義的項目順序。那就是OrderedDict.

      核心 Python 開發(fā)人員希望填補空白并提供一個可以保留插入鍵順序的字典。反過來,這允許更直接地實現(xiàn)依賴此屬性的特定算法。

      OrderedDict在Python 3.1 中被添加到標準庫中。它的 API 與dict.?但是,OrderedDict以插入鍵的相同順序迭代鍵和值。如果新條目覆蓋現(xiàn)有條目,則項目的順序保持不變。如果一個條目被刪除并重新插入,那么它將被移動到字典的末尾。

      Python的3.6引入了一個新的實現(xiàn)dict。這種新的實現(xiàn)代表了內(nèi)存使用和迭代效率方面的巨大勝利。此外,新的實現(xiàn)提供了一個新的、有點出乎意料的特性:dict對象現(xiàn)在保持它們的項目與它們被引入的順序相同。最初,這個特性被認為是一個實現(xiàn)細節(jié),文檔建議不要依賴它。

      注:在本教程中,你會注重的實現(xiàn)dict和OrderedDict那CPython的提供。

      用核心 Python 開發(fā)人員和 的合著者Raymond Hettinger的話來說OrderedDict,該類專門設計用于保持其項目有序,而 的新實現(xiàn)dict旨在緊湊并提供快速迭代:

      目前的正則詞典是基于我?guī)啄昵疤岢龅脑O計。該設計的主要目標是在密集的鍵和值數(shù)組上實現(xiàn)緊湊性和更快的迭代。維持秩序是一種人工制品,而不是設計目標。設計可以維持秩序,但這不是它的專長。

      相比之下,我給出了collections.OrderedDict一個不同的設計(后來由 Eric Snow 用 C 編碼)。主要目標是即使在繁重的工作負載下也能有效維護秩序,例如lru_cache經(jīng)常改變秩序而不觸及底層的dict。有意地,OrderedDict它的設計以額外的內(nèi)存開銷和更差的插入時間為代價,優(yōu)先考慮排序功能。

      我的目標仍然是collections.OrderedDict擁有與常規(guī) dicts 不同的性能特征的不同設計。它有一些常規(guī)字典沒有的特定于訂單的方法(例如從任一端有效彈出的amove_to_end()和 a?popitem())。在OrderedDict需要善于那些操作,因為這是與常規(guī)類型的字典相區(qū)別。(來源)

      在Python 3.7 中,dict對象的按項目排序的特性被宣布為 Python 語言規(guī)范的正式部分。因此,從那時起,開發(fā)人員可以依靠dict何時需要一個字典來保持其項目的有序性。

      此時,一個問題出現(xiàn)了:OrderedDict這個新的實現(xiàn)之后還需要dict嗎?答案取決于您的特定用例以及您希望在代碼中的明確程度。

      在撰寫本文時, 的某些功能OrderedDict仍然使其有價值且與常規(guī) 不同dict:

      意圖信號:如果您使用OrderedDictover?dict,那么您的代碼會清楚地表明字典中項目的順序很重要。您清楚地傳達了您的代碼需要或依賴于底層字典中項目的順序。

      控制項目的順序:如果您需要重新安排或重新排序在字典中的項目,那么你可以使用.move_to_end()并且還增強變化.popitem()。

      相等測試行為:如果您的代碼比較字典是否相等,并且項目的順序在該比較中很重要,那么OrderedDict它就是正確的選擇。

      至少還有一個理由可以OrderedDict在您的代碼中繼續(xù)使用:向后兼容性。在dict運行 Python 3.6 之前版本的環(huán)境中,依靠常規(guī)對象來保留項目的順序會破壞您的代碼。

      很難說是否dict會OrderedDict很快完全取代。如今,OrderedDict仍然提供有趣且有價值的功能,您在為給定工作選擇工具時可能需要考慮這些功能。

      Python 入門?OrderedDict

      PythonOrderedDict是一個dict子類,它保留鍵值對(通常稱為items)插入字典的順序。當您迭代一個OrderedDict對象時,項目將按原始順序遍歷。如果您更新現(xiàn)有鍵的值,則訂單保持不變。如果您刪除一個項目并重新插入它,那么該項目將添加到字典的末尾。

      作為dict子類意味著它繼承了常規(guī)字典提供的所有方法。OrderedDict還具有您將在本教程中了解的其他功能。但是,在本節(jié)中,您將學習OrderedDict在代碼中創(chuàng)建和使用對象的基礎知識。

      創(chuàng)建OrderedDict對象

      與 不同dict,OrderedDict不是內(nèi)置類型,因此創(chuàng)建OrderedDict對象的第一步是從導入類collections。有多種方法可以創(chuàng)建有序字典。它們中的大多數(shù)與您創(chuàng)建常規(guī)dict對象的方式相同。例如,您可以OrderedDict通過實例化不帶參數(shù)的類來創(chuàng)建一個空對象:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict() >>> numbers["one"] = 1 >>> numbers["two"] = 2 >>> numbers["three"] = 3 >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)])

      在這種情況下,您首先OrderedDict從collections.?然后通過實例化OrderedDict而不向構造函數(shù)提供參數(shù)來創(chuàng)建一個空的有序字典。

      您可以通過在方括號 (?[]) 中提供一個鍵并為該鍵分配一個值來將鍵值對添加到字典中。當您引用 時numbers,您將獲得一個可迭代的鍵值對,這些鍵值對以它們插入字典的相同順序保存項目。

      您還可以將一個可迭代的項目作為參數(shù)傳遞給以下的構造函數(shù)OrderedDict:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict([("one", 1), ("two", 2), ("three", 3)]) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)]) >>> letters = OrderedDict({("a", 1), ("b", 2), ("c", 3)}) >>> letters OrderedDict([('c', 3), ('a', 1), ('b', 2)])

      當您使用序列(例如 alist或 a )時tuple,生成的有序字典中項目的順序與輸入序列中項目的原始順序相匹配。如果您使用 a?set,就像上面的第二個示例一樣,那么在OrderedDict創(chuàng)建之前,項目的最終順序是未知的。

      如果您使用常規(guī)字典作為OrderedDict對象的初始值設定項,并且您使用的是 Python 3.6 或更高版本,那么您將獲得以下行為:

      >>>

      Python 3.9.0 (default, Oct 5 2020, 17:52:02) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from collections import OrderedDict >>> numbers = OrderedDict({"one": 1, "two": 2, "three": 3}) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)])

      OrderedDict對象中項目的順序與原始字典中的順序匹配。另一方面,如果您使用的是低于 3.6 的 Python 版本,則項目的順序是未知的:

      >>>

      Python 3.5.10 (default, Jan 25 2021, 13:22:52) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from collections import OrderedDict >>> numbers = OrderedDict({"one": 1, "two": 2, "three": 3}) >>> numbers OrderedDict([('one', 1), ('three', 3), ('two', 2)])

      由于 Python 3.5 中的字典不記得它們項的順序,因此在創(chuàng)建對象之前您不知道結果有序字典中的順序。從這點開始,訂單保持不變。

      您可以通過將關鍵字參數(shù)傳遞給類構造函數(shù)來創(chuàng)建有序字典:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)])

      自Python 3.6 起,函數(shù)保留在調(diào)用中傳遞的關鍵字參數(shù)的順序。因此,上述項目OrderedDict的順序與您將關鍵字參數(shù)傳遞給構造函數(shù)的順序相匹配。在早期的 Python 版本中,該順序是未知的。

      最后,OrderedDict還提供了.fromkeys(),它從一個可迭代的鍵創(chuàng)建一個新字典,并將其所有值設置為一個公共值:

      >>>

      >>> from collections import OrderedDict >>> keys = ["one", "two", "three"] >>> OrderedDict.fromkeys(keys, 0) OrderedDict([('one', 0), ('two', 0), ('three', 0)])

      在這種情況下,您使用鍵列表作為起點創(chuàng)建一個有序字典。的第二個參數(shù)為.fromkeys()字典中的所有項目提供一個值。

      管理項目?OrderedDict

      由于OrderedDict是可變數(shù)據(jù)結構,您可以對其實例執(zhí)行變異操作。您可以插入新項目、更新和刪除現(xiàn)有項目等。如果您將新項目插入現(xiàn)有的有序字典,則該項目將添加到字典的末尾:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)]) >>> numbers["four"] = 4 >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3), ('four', 4)])

      新添加的項,('four', 4),放置在底層字典的末尾,因此現(xiàn)有項的順序不受影響,字典保持插入順序。

      如果您從現(xiàn)有的有序字典中刪除一個項目并再次插入相同的項目,則該項目的新實例將放置在字典的末尾:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> del numbers["one"] >>> numbers OrderedDict([('two', 2), ('three', 3)]) >>> numbers["one"] = 1 >>> numbers OrderedDict([('two', 2), ('three', 3), ('one', 1)])

      如果刪除('one', 1)項目并插入同一項目的新實例,則新項目將添加到基礎字典的末尾。

      如果您重新分配或更新OrderedDict對象中現(xiàn)有鍵值對的值,則鍵保持其位置但獲得新值:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers["one"] = 1.0 >>> numbers OrderedDict([('one', 1.0), ('two', 2), ('three', 3)]) >>> numbers.update(two=2.0) >>> numbers OrderedDict([('one', 1.0), ('two', 2.0), ('three', 3)])

      如果更新有序字典中給定鍵的值,則鍵不會移動,而是在適當?shù)奈恢梅峙湫轮?。同理,如果?update()用來修改現(xiàn)有的鍵值對的值,那么字典會記住鍵的位置,并將更新后的值賦給它。

      迭代一個?OrderedDict

      就像使用常規(guī)詞典一樣,您可以使用多種工具和技術遍歷一個OrderedDict對象。您可以直接遍歷鍵,也可以使用字典方法,例如.items()、.keys()、 和.values():

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> # Iterate over the keys directly >>> for key in numbers: ... print(key, "->", numbers[key]) ... one -> 1 two -> 2 three -> 3 >>> # Iterate over the items using .items() >>> for key, value in numbers.items(): ... print(key, "->", value) ... one -> 1 two -> 2 three -> 3 >>> # Iterate over the keys using .keys() >>> for key in numbers.keys(): ... print(key, "->", numbers[key]) ... one -> 1 two -> 2 three -> 3 >>> # Iterate over the values using .values() >>> for value in numbers.values(): ... print(value) ... 1 2 3

      第一個for循環(huán)numbers直接迭代 的鍵。其他三個循環(huán)使用字典方法來迭代 的項、鍵和值numbers。

      以相反的順序迭代?reversed()

      OrderedDict自Python 3.5以來提供的另一個重要特性是它的項、鍵和值支持使用reversed().?此功能已添加到Python 3.8 中的常規(guī)詞典中。因此,如果您的代碼使用它,那么您的向后兼容性將受到普通詞典的更多限制。

      您可以使用對象reversed()的項、鍵和值OrderedDict:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> # Iterate over the keys directly in reverse order >>> for key in reversed(numbers): ... print(key, "->", numbers[key]) ... three -> 3 two -> 2 one -> 1 >>> # Iterate over the items in reverse order >>> for key, value in reversed(numbers.items()): ... print(key, "->", value) ... three -> 3 two -> 2 one -> 1 >>> # Iterate over the keys in reverse order >>> for key in reversed(numbers.keys()): ... print(key, "->", numbers[key]) ... three -> 3 two -> 2 one -> 1 >>> # Iterate over the values in reverse order >>> for value in reversed(numbers.values()): ... print(value) ... 3 2 1

      此示例中的每個循環(huán)都用于reversed()以相反的順序遍歷有序字典的不同元素。

      常規(guī)詞典也支持反向迭代。但是,如果您嘗試在低于 3.8 的 Python 版本中使用reversed()常規(guī)dict對象,則會得到TypeError:

      >>>

      Python 3.7.9 (default, Jan 14 2021, 11:41:20) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> numbers = dict(one=1, two=2, three=3) >>> for key in reversed(numbers): ... print(key) ... Traceback (most recent call last): File "", line 1, in TypeError: 'dict' object is not reversible

      如果您需要以相反的順序迭代字典中的項目,那么它OrderedDict是一個很好的盟友。使用常規(guī)字典會顯著降低向后兼容性,因為反向迭代直到 Python 3.8 才添加到常規(guī)字典中。

      探索 Python 的獨特功能?OrderedDict

      從 Python 3.6 開始,常規(guī)詞典將它們的項目按照它們插入底層詞典的順序保存。OrderedDict正如您目前所見,這限制了 的用處。但是,OrderedDict提供了一些在常規(guī)dict對象中找不到的獨特功能。

      使用有序字典,您可以訪問以下額外和增強的方法:

      .move_to_end()是Python 3.2中添加的一種新方法,它允許您將現(xiàn)有項目移動到字典的末尾或開頭。

      .popitem()是其dict.popitem()對應物的增強變體,允許您從底層有序字典的末尾或開頭刪除和返回項目。

      OrderedDict并且dict也表現(xiàn)不同,當他們爭取平等的測試。具體來說,當您比較有序字典時,項目的順序很重要。普通字典不是這種情況。

      最后,OrderedDict實例提供了一個.__dict__在常規(guī)字典實例中找不到的屬性。此屬性允許您將自定義可寫屬性添加到現(xiàn)有的有序字典中。

      重新排序項目?.move_to_end()

      dict和之間更顯著的區(qū)別之一OrderedDict是后者有一個名為 的額外方法.move_to_end()。此方法允許您將現(xiàn)有項目移動到底層字典的末尾或開頭,因此它是重新排序字典的絕佳工具。

      使用時.move_to_end(),您可以提供兩個參數(shù):

      key持有標識您要移動的項目的鍵。如果key不存在,那么你會得到一個KeyError.

      last持有一個布爾值,該值定義您要將手頭的項目移動到字典的哪一端。它默認為True,這意味著該項目將移動到字典的末尾或右側。False意味著該項目將被移動到有序字典的前面或左側。

      下面是如何使用的例子.move_to_end()有一個key參數(shù),依靠的默認值last:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)]) >>> numbers.move_to_end("one") >>> numbers OrderedDict([('two', 2), ('three', 3), ('one', 1)])

      當您.move_to_end()使用 akey作為參數(shù)調(diào)用時,您將手頭的鍵值對移動到字典的末尾。這就是為什么('one', 1)現(xiàn)在處于最后的位置。請注意,其余項目保持相同的原始順序。

      如果傳遞False給last,則將項目移至開頭:

      >>>

      >>> numbers.move_to_end("one", last=False) >>> numbers OrderedDict([('one', 1), ('two', 2), ('three', 3)])

      在這種情況下,您將移至('one', 1)字典的開頭。這提供了一個有趣且強大的功能。例如,使用.move_to_end(),您可以按鍵對有序字典進行排序:

      >>>

      >>> from collections import OrderedDict >>> letters = OrderedDict(b=2, d=4, a=1, c=3) >>> for key in sorted(letters): ... letters.move_to_end(key) ... >>> letters OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])

      在本例中,您首先創(chuàng)建一個有序字典letters.?該for環(huán)路的排序鍵和移動每一個項目遍歷到字典中結束。循環(huán)完成后,您的有序字典將按鍵對其項目進行排序。

      按值對字典進行排序將是一個有趣的練習,因此請展開下面的塊并嘗試一下!

      練習:按值對字典進行排序顯示隱藏

      您可以展開下面的塊以查看可能的解決方案。

      解決方案:按值對字典進行排序顯示隱藏

      偉大的!您現(xiàn)在知道如何使用.move_to_end().?您已準備好進入下一部分。

      刪除項目?.popitem()

      另一個有趣的功能OrderedDict是它的增強版.popitem().?默認情況下,.popitem()以LIFO(后進/先出)順序刪除和返回項目。換句話說,它從有序字典的右端刪除項目:

      Python 中的 OrderedDict 與 dict:適合工作的正確工具(python是什么意思)

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers.popitem() ('three', 3) >>> numbers.popitem() ('two', 2) >>> numbers.popitem() ('one', 1) >>> numbers.popitem() Traceback (most recent call last): File "", line 1, in numbers.popitem() KeyError: 'dictionary is empty'

      在這里,您從numbers使用中刪除所有項目.popitem()。每次調(diào)用此方法都會從底層字典的末尾刪除一個項目。如果你調(diào)用.popitem()一個空字典,那么你會得到一個KeyError.?到目前為止,.popitem()其行為與常規(guī)詞典中的行為相同。

      OrderedDict但是,In.popitem()也接受一個名為 的布爾參數(shù)last,默認為True。如果設置last為False,.popitem()則以FIFO(先進/先出)順序刪除項目,這意味著它從字典的開頭刪除項目:

      >>>

      >>> from collections import OrderedDict >>> numbers = OrderedDict(one=1, two=2, three=3) >>> numbers.popitem(last=False) ('one', 1) >>> numbers.popitem(last=False) ('two', 2) >>> numbers.popitem(last=False) ('three', 3) >>> numbers.popitem(last=False) Traceback (most recent call last): File "", line 1, in numbers.popitem(last=False) KeyError: 'dictionary is empty'

      隨著last集來True,你可以使用.popitem()從一個有序字典的開頭刪除和回報的項目。在這個例子中,最后一次調(diào)用.popitem()引發(fā) aKeyError因為底層字典已經(jīng)是空的。

      測試字典之間的相等性

      當您OrderedDict在布爾上下文中測試兩個對象的相等性時,項目的順序起著重要的作用。例如,如果您訂購的字典包含相同的項目集,則測試結果取決于它們的順序:

      >>>

      >>> from collections import OrderedDict >>> letters_0 = OrderedDict(a=1, b=2, c=3, d=4) >>> letters_1 = OrderedDict(b=2, a=1, c=3, d=4) >>> letters_2 = OrderedDict(a=1, b=2, c=3, d=4) >>> letters_0 == letters_1 False >>> letters_0 == letters_2 True

      在本例中,letters_1與letters_0和相比,其項目的順序略有不同letters_2,因此第一個測試返回False。在第二次測試中,letters_0并且letters_2具有相同的項目集,它們的順序相同,因此測試返回True。

      如果您使用常規(guī)詞典嘗試相同的示例,則會得到不同的結果:

      >>>

      >>> letters_0 = dict(a=1, b=2, c=3, d=4) >>> letters_1 = dict(b=2, a=1, c=3, d=4) >>> letters_2 = dict(a=1, b=2, c=3, d=4) >>> letters_0 == letters_1 True >>> letters_0 == letters_2 True >>> letters_0 == letters_1 == letters_2 True

      在這里,當您測試兩個常規(guī)詞典是否相等時,您會得到True兩個詞典是否具有相同的項目集。在這種情況下,項目的順序不會改變最終結果。

      最后,OrderedDict對象和常規(guī)字典之間的相等性測試不考慮項目的順序:

      >>>

      >>> from collections import OrderedDict >>> letters_0 = OrderedDict(a=1, b=2, c=3, d=4) >>> letters_1 = dict(b=2, a=1, c=3, d=4) >>> letters_0 == letters_1 True

      當您將有序詞典與常規(guī)詞典進行比較時,項目的順序無關緊要。如果兩個字典具有相同的項目集,則無論項目的順序如何,它們的比較都是相同的。

      將新屬性附加到字典實例

      OrderedDict對象具有.__dict__在常規(guī)字典對象中找不到的屬性。看看下面的代碼:

      >>>

      >>> from collections import OrderedDict >>> letters = OrderedDict(b=2, d=4, a=1, c=3) >>> letters.__dict__ {} >>> letters1 = dict(b=2, d=4, a=1, c=3) >>> letters1.__dict__ Traceback (most recent call last): File "", line 1, in letters1.__dict__ AttributeError: 'dict' object has no attribute '__dict__'

      在第一個示例中,您訪問.__dict__有序字典上的屬性letters。Python 內(nèi)部使用此屬性來存儲可寫的實例屬性。第二個示例顯示常規(guī)字典對象沒有.__dict__屬性。

      您可以使用有序字典的.__dict__屬性來存儲動態(tài)創(chuàng)建的可寫實例屬性。有幾種方法可以做到這一點。例如,您可以使用字典樣式的賦值,例如 in?ordered_dict.__dict__["attr"] = value。您還可以使用點表示法,例如在ordered_dict.attr = value.

      這是.__dict__用于將新函數(shù)附加到現(xiàn)有有序字典的示例:

      >>>

      >>> from collections import OrderedDict >>> letters = OrderedDict(b=2, d=4, a=1, c=3) >>> letters.sorted_keys = lambda: sorted(letters.keys()) >>> vars(letters) {'sorted_keys': at 0x7fa1e2fe9160>} >>> letters.sorted_keys() ['a', 'b', 'c', 'd'] >>> letters["e"] = 5 >>> letters.sorted_keys() ['a', 'b', 'c', 'd', 'e']

      現(xiàn)在,您的有序字典附加了一個.sorted_keys()?lambda函數(shù)letters。請注意,您可以通過使用點符號.__dict__直接訪問或使用.vars()

      注意:這種動態(tài)屬性被添加到給定類的特定實例中。在上面的示例中,該實例是letters。這既不會影響其他實例,也不會影響類本身,因此您只能訪問.sorted_keys()through?letters。

      您可以使用此動態(tài)添加的函數(shù)按排序順序遍歷字典鍵,而無需更改 中的原始順序letters:

      >>>

      >>> for key in letters.sorted_keys(): ... print(key, "->", letters[key]) ... a -> 1 b -> 2 c -> 3 d -> 4 e -> 5 >>> letters OrderedDict([('b', 2), ('d', 4), ('a', 1), ('c', 3), ('e', 5)])

      這只是說明此功能的有用性的一個示例OrderedDict。請注意,您不能用普通字典做類似的事情:

      >>>

      >>> letters = dict(b=2, d=4, a=1, c=3) >>> letters.sorted_keys = lambda: sorted(letters.keys()) Traceback (most recent call last): File "", line 1, in letters.sorted_keys = lambda: sorted(letters.keys()) AttributeError: 'dict' object has no attribute 'sorted_keys'

      如果您嘗試將自定義實例屬性動態(tài)添加到常規(guī)字典,那么您會得到一個消息,AttributeError告訴您底層字典沒有該屬性。那是因為常規(guī)詞典沒有一個.__dict__屬性來保存新的實例屬性。

      使用運算符合并和更新字典

      Python 3.9向字典空間添加了兩個新運算符?,F(xiàn)在您有了合并(?|) 和更新(?|=) 字典運算符。這些運算符也適用于OrderedDict實例:

      >>>

      Python 3.9.0 (default, Oct 5 2020, 17:52:02) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from collections import OrderedDict >>> physicists = OrderedDict(newton="1642-1726", einstein="1879-1955") >>> biologists = OrderedDict(darwin="1809-1882", mendel="1822-1884") >>> scientists = physicists | biologists >>> scientists OrderedDict([ ('newton', '1642-1726'), ('einstein', '1879-1955'), ('darwin', '1809-1882'), ('mendel', '1822-1884') ])

      顧名思義,合并運算符將兩個字典合并為一個包含兩個初始字典項的新字典。如果表達式中的字典有公共鍵,那么最右邊的字典的值將優(yōu)先。

      當你有一個字典并且想要更新它的一些值而不調(diào)用時,更新操作符很方便.update():

      >>>

      >>> physicists = OrderedDict(newton="1642-1726", einstein="1879-1955") >>> physicists_1 = OrderedDict(newton="1642-1726/1727", hawking="1942-2018") >>> physicists |= physicists_1 >>> physicists OrderedDict([ ('newton', '1642-1726/1727'), ('einstein', '1879-1955'), ('hawking', '1942-2018') ])

      在本例中,您使用字典更新運算符來更新牛頓的生命周期信息。操作員就地更新字典。如果提供更新數(shù)據(jù)的字典有新的鍵,那么這些鍵會被添加到原始字典的末尾。

      考慮性能

      性能是編程中的一個重要主題。了解算法運行的速度或使用的內(nèi)存量是常見的問題。OrderedDict最初是用 Python編寫的,然后用 C 編寫,以最大限度地提高其方法和操作的效率。這兩個實現(xiàn)目前在標準庫中可用。但是,如果 C 實現(xiàn)由于某種原因不可用,則 Python 實現(xiàn)可作為替代方案。

      的兩種實現(xiàn)都OrderedDict涉及使用雙向鏈表來捕獲項目的順序。盡管某些操作具有線性時間,但 中的鏈表實現(xiàn)OrderedDict已高度優(yōu)化以保留相應字典方法的快速時間。也就是說,對有序字典的操作是O?(1)但與常規(guī)字典相比具有更大的常數(shù)因子。

      一般來說,OrderedDict性能比普通詞典低。這是一個測量兩個字典類上幾個操作的執(zhí)行時間的示例:

      # time_testing.py from collections import OrderedDict from time import perf_counter def average_time(dictionary): time_measurements = [] for _ in range(1_000_000): start = perf_counter() dictionary["key"] = "value" "key" in dictionary "missing_key" in dictionary dictionary["key"] del dictionary["key"] end = perf_counter() time_measurements.append(end - start) return sum(time_measurements) / len(time_measurements) * int(1e9) ordereddict_time = average_time(OrderedDict.fromkeys(range(1000))) dict_time = average_time(dict.fromkeys(range(1000))) gain = ordereddict_time / dict_time print(f"OrderedDict: {ordereddict_time:.2f} ns") print(f"dict: {dict_time:.2f} ns ({gain:.2f}x faster)")

      在此腳本中,您計算 在average_time()給定字典上運行多個常見操作所需的時間。該for循環(huán)使用time.pref_counter()測量組操作的執(zhí)行時間。該函數(shù)返回運行所選操作集所需的平均時間(以納秒為單位)。

      注意:如果您有興趣了解為代碼計時的其他方法,那么您可以查看Python 計時器函數(shù):監(jiān)視代碼的三種方法。

      如果從命令行運行此腳本,則會得到類似于以下內(nèi)容的輸出:

      $ python time_testing.py OrderedDict: 272.93 ns dict: 197.88 ns (1.38x faster)

      正如您在輸出中看到的,對dict對象的操作比對OrderedDict對象的操作快。

      關于內(nèi)存消耗,OrderedDict實例必須支付存儲成本,因為它們是有序的鍵列表。這是一個腳本,可讓您了解此內(nèi)存成本:

      >>>

      >>> import sys >>> from collections import OrderedDict >>> ordereddict_memory = sys.getsizeof(OrderedDict.fromkeys(range(1000))) >>> dict_memory = sys.getsizeof(dict.fromkeys(range(1000))) >>> gain = 100 - dict_memory / ordereddict_memory * 100 >>> print(f"OrderedDict: {ordereddict_memory} bytes") OrderedDict: 85408 bytes >>> print(f"dict: {dict_memory} bytes ({gain:.2f}% lower)") dict: 36960 bytes (56.73% lower)

      在此示例中,您使用sys.getsizeof()以字節(jié)為單位測量兩個字典對象的內(nèi)存占用。在輸出中,您可以看到常規(guī)字典比其OrderedDict對應字典占用更少的內(nèi)存。

      為工作選擇合適的詞典

      到目前為止,您已經(jīng)了解了OrderedDict和之間的細微差別dict。您已經(jīng)了解到,盡管自 Python 3.6 以來常規(guī)字典已被排序為數(shù)據(jù)結構,但仍然有一些使用價值,OrderedDict因為dict.

      以下是您在決定使用哪個類時應考慮的兩個類的更相關差異和功能的摘要:

      下表總結了當您需要選擇字典類來解決問題或實現(xiàn)特定算法時,您應該考慮OrderedDict和兩者之間的一些主要區(qū)別dict。一般來說,如果字典中項目的順序對您的代碼正常工作至關重要甚至很重要,那么您的第一眼應該是OrderedDict.

      構建基于字典的隊列

      您應該考慮使用OrderedDict對象而不是dict對象的用例是當您需要實現(xiàn)基于字典的queue 時。隊列是常見且有用的數(shù)據(jù)結構,以先進先出的方式管理其項目。這意味著您在隊列末尾推入新項目,而舊項目從隊列開頭彈出。

      通常,隊列會實現(xiàn)一個將項目添加到其末尾的操作,這稱為入隊操作。隊列還實現(xiàn)了從頭開始刪除項目的操作,這稱為出隊操作。

      要創(chuàng)建基于字典的隊列,請啟動您的代碼編輯器或 IDE,創(chuàng)建一個名為的新 Python 模塊queue.py并向其中添加以下代碼:

      # queue.py from collections import OrderedDict class Queue: def __init__(self, initial_data=None, /, **kwargs): self.data = OrderedDict() if initial_data is not None: self.data.update(initial_data) if kwargs: self.data.update(kwargs) def enqueue(self, item): key, value = item if key in self.data: self.data.move_to_end(key) self.data[key] = value def dequeue(self): try: return self.data.popitem(last=False) except KeyError: print("Empty queue") def __len__(self): return len(self.data) def __repr__(self): return f"Queue({self.data.items()})"

      在 中Queue,您首先初始化一個名為的實例屬性.data。此屬性包含一個空的有序字典,您將使用它來存儲數(shù)據(jù)。類初始值設定項采用第一個可選參數(shù) ,initial_data它允許您在實例化類時提供初始數(shù)據(jù)。初始值設定項還采用可選的關鍵字參數(shù) (?kwargs) 以允許您在構造函數(shù)中使用關鍵字參數(shù)。

      然后您編寫代碼.enqueue(),它允許您將鍵值對添加到隊列中。在這種情況下,.move_to_end()如果鍵已經(jīng)存在,則使用,并且對新鍵使用正常分配。請注意,要使此方法起作用,您需要提供兩個項目tuple或list一個有效的鍵值對。

      該.dequeue()實現(xiàn)使用.popitem()with?lastset toFalse從底層有序字典的開頭刪除和返回項目,.data。在這種情況下,您可以使用try...except塊來處理KeyError調(diào)用.popitem()空字典時發(fā)生的情況。

      特殊方法.__len__()提供了檢索內(nèi)部有序字典長度所需的功能,.data。最后,當您將數(shù)據(jù)結構打印到屏幕時,特殊方法.__repr__()提供了隊列的用戶友好字符串表示。

      以下是一些如何使用的示例Queue:

      >>>

      >>> from queue import Queue >>> # Create an empty queue >>> empty_queue = Queue() >>> empty_queue Queue(odict_items([])) >>> # Create a queue with initial data >>> numbers_queue = Queue([("one", 1), ("two", 2)]) >>> numbers_queue Queue(odict_items([('one', 1), ('two', 2)])) >>> # Create a queue with keyword arguments >>> letters_queue = Queue(a=1, b=2, c=3) >>> letters_queue Queue(odict_items([('a', 1), ('b', 2), ('c', 3)])) >>> # Add items >>> numbers_queue.enqueue(("three", 3)) >>> numbers_queue Queue(odict_items([('one', 1), ('two', 2), ('three', 3)])) >>> # Remove items >>> numbers_queue.dequeue() ('one', 1) >>> numbers_queue.dequeue() ('two', 2) >>> numbers_queue.dequeue() ('three', 3) >>> numbers_queue.dequeue() Empty queue

      在此代碼示例中,您首先Queue使用不同的方法創(chuàng)建三個不同的對象。然后您使用.enqueue()將單個項目添加到numbers_queue.?最后,您.dequeue()多次調(diào)用以刪除numbers_queue.?請注意,最后一次調(diào)用會.dequeue()在屏幕上打印一條消息,通知您隊列已為空。

      結論

      多年來,Python 字典都是無序的數(shù)據(jù)結構。這表明需要一個有序的字典來幫助項目的順序很重要的情況。因此,Python 開發(fā)人員創(chuàng)建了OrderedDict,專門設計用于保持其項目有序。

      Python 3.6 在常規(guī)詞典中引入了一項新功能。現(xiàn)在他們也記住了物品的順序。有了這個添加,大多數(shù) Python 程序員想知道他們是否仍然需要考慮使用OrderedDict.

      在本教程中,您學習了:

      如何在代碼中創(chuàng)建和使用OrderedDict對象

      和之間的主要區(qū)別是什么OrderedDictdict

      什么優(yōu)點和缺點是使用OrderedDictVSdict

      現(xiàn)在,您可以更好地就是否使用dict或OrderedDict您的代碼是否需要有序字典做出明智的決定。

      在本教程中,您編寫了一個關于如何實現(xiàn)基于字典的隊列的示例,這是一個用例,表明它OrderedDict在您的日常 Python 編碼冒險中仍然很有價值。

      Python 數(shù)據(jù)結構

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      上一篇:WPS表格求標準差的方法步驟詳解(wps標準差怎么算?附步驟)
      下一篇:wps表格怎么增加行圖文教程(wpsword表格怎么增加行)
      相關文章
      国产亚洲日韩在线a不卡| 亚洲欧洲精品一区二区三区| 亚洲视频免费在线观看| 亚洲一区二区三区免费| 亚洲av成人一区二区三区在线播放| 亚洲人成自拍网站在线观看| 久久亚洲国产成人影院| 亚洲一区无码中文字幕乱码| 亚洲一卡二卡三卡四卡无卡麻豆| 亚洲精品视频专区| 67pao强力打造67194在线午夜亚洲| 亚洲小视频在线观看| 久久久久无码精品亚洲日韩| 久久亚洲精品国产精品黑人| 亚洲AV无码日韩AV无码导航| 亚洲成人在线网站| 亚洲欧洲日产韩国在线| 亚洲大尺码专区影院| 亚洲综合校园春色| 亚洲熟妇无码一区二区三区导航| 亚洲人片在线观看天堂无码| 国产成人精品亚洲一区| 亚洲精品视频免费| 丝袜熟女国偷自产中文字幕亚洲| 亚洲日韩中文无码久久| 亚洲国产精品国自产电影| 久久亚洲精精品中文字幕| 亚洲成在人线中文字幕| 国产精品高清视亚洲精品| 亚洲女女女同性video| 337p日本欧洲亚洲大胆人人| 国产亚洲美女精品久久久久| 亚洲另类少妇17p| 国产亚洲成AV人片在线观黄桃 | 日本久久久久亚洲中字幕| 亚洲精品综合久久中文字幕| va天堂va亚洲va影视中文字幕| 中文无码亚洲精品字幕| 最新亚洲人成无码网www电影| 亚洲国产成人精品女人久久久 | 亚洲精选在线观看|