精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Python 的 OrderedDict 為什么有序?

開發 前端
為什么選擇一個 ??object()?? 作為默認值?這是因為,此處需要通過 ??pop(...)?? 的返回值來嚴格區分“key 存在”和“key 不存在”兩種情況。所以,一個絕不可能在用戶字典中出現的新鮮熱乎的 ??object()?? 對象,是最為理想的默認值選擇。

現在是 2025 年,網上已很少見到 Python 字典有序性的相關討論。自從 Python 在 2018 年發布 3.7 版本,將“字典保持成員的插入序”寫進語言規范后,人們已漸漸習慣有序的字典。那曾經調皮、無序的字典,早已像 2.7 版本一樣成為過去,只在某些老登們憶苦思甜時被提起。

而在那個字典無法保持順序的年代,如果我們要用到有序的字典,我們用什么?答案是:collections.OrderedDict

但是,隨著內置字典已經有序,OrderedDict 似乎也漸漸變得不再必要。不過,截止到目前(3.14 版本)為止,它仍然存在于標準庫模塊 collections 中。這主要是出于以下幾個原因:

  • 保持向前兼容,已依賴其的舊代碼可以保持不變;
  • 行為不同:OrderedDict 在判斷相等性時會將鍵順序納入考量,內置字典不會;
  • 更多特性:OrderedDict 擁有 move_to_end 等方法。
>>> d
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> d.move_to_end('a')
>>> d
OrderedDict([('b', 2), ('c', 3), ('a', 1)])    # 1
  •  move_to_end()  可以把某個鍵移動到字典的末尾

本文將深入 OrderedDict 類型的內部實現,了解在 Python 中實現一個有序的字典,需要做哪些工作。

注:具體來說,標準庫中的 OrderedDict 數據結構有 C 和 Python 兩套不同實現,各自適用不同的運行環境,二者的實現類似;本文針對 Python 版本編寫。

一個雙向鏈表和另一個字典

OrderedDict 是一個有序的字典,它像普通字典一樣支持鍵值對操作,只是保留了鍵的順序。實現 OrderedDict 的關鍵在于以下兩點:

1. 繼承 dict:自動擁有內置字典類型的所有操作,所有鍵值對存放在 OrderedDict 對象自身中——self 就是一個 {}

2. 引入額外數據結構:引入額外的有序數據結構,讓其作為一種外部參考來維護鍵的順序。

數據結構有很多種,到底該使用哪一種來維持鍵的有序性?由于字典是一種基于哈希表(hash table)的高性能結構,最擅長在 O(1) 的時間復雜度下完成鍵值對的存取操作。因此,OrderedDict 所需的用于保存鍵順序的額外結構,首先應滿足性能要求——“維護順序”的過程不能拖慢字典的原操作。

為了達到這個目標,OrderedDict 同時使用了兩個數據結構:一個雙向鏈表和另一個字典。

1. 雙向鏈表:有序結構,根據鏈表節點可以方便地在鏈表中新增或刪除成員(時間復雜度為 O(1)),節點所保存的內容為 OrderedDict 的鍵名。

2. 另一個字典:在鏈表中查詢一個節點,通常需要按序遍歷完所有節點,平均時間復雜度是 O(n),這顯然不滿足性能需求,因此 OrderedDict 引入了另一個字典作為鏈表的索引,使用鍵可快速拿到鏈表節點(時間復雜度 O(1))。

整個數據結構如下圖所示:

圖:OrderedDict 內部數據結構示意圖,包含三大數據結構:self(保存鍵值對的字典自身)、self.root...(有序雙向鏈表)、self._map(鏈表索引字典)

下面以 __setitem__ 方法為例,詳細看看 OrderedDict 如何完成鍵值對的寫操作,以下是相關代碼:

def __setitem__(self, key, value,
                    dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
        'od.__setitem__(i, y) <==> od[i]=y'
        if key not in self:
            self.__map[key] = link = Link()  # 1
            root = self.__root
            last = root.prev
            link.prev, link.next, link.key = last, root, key  # 2
            last.next = link
            root.prev = proxy(link)  # 3
        dict_setitem(self, key, value)  # 4

1. 創建一個新的鏈表節點,并將其存放到 self.__map 中,之后可以通過 key 來快速讀取該節點;

2. 修改新節點 link 的前后節點,將其插入到 root 前,也就是作為尾部節點加入鏈表;

3. 修改另外兩個相關節點 last(原尾節點)和 root(根節點),至此完成整套鏈表操作;

4. 修改自身字典中的對應鍵值對。

假設執行代碼 d["aa"] = 4,往字典中插入一個新成員,整套數據的變化如下圖所示:

圖:插入鍵值對 "aa": 4,OrderedDict 內部數據結構發生的變化圖:插入鍵值對 "aa": 4,OrderedDict 內部數據結構發生的變化

雙向鏈表、鏈表索引字典,以及 OrderedDict 字典自身,都需要處理 "aa": 4 這個新成員。

同 __setitem__() 類似,__delitem__()(刪除成員)和 pop()(彈出成員)方法除修改自身字典外,也需要調整對應鍵在鏈表和索引字典中的數據狀態,在此不再贅述。

為了讓 OrderedDict 在被迭代時能有序返回所有鍵, __iter__ 方法也需要有所調整,下面是相關代碼:

def __iter__(self):
    'od.__iter__() <==> iter(od)'
    root = self.__root
    curr = root.next
    while curr is not root:
        yield curr.key
        curr = curr.next

可以看出,遍歷一個 OrderedDict,實際上就是在遍歷它內部的雙向鏈表。遍歷由一個 while 循環完成,它將鏈表中每個節點通過生成器返回,從而實現有序。

小結

通過引入額外的數據結構,OrderedDict 最終實現了有序。雙向鏈表加索引字典的組合,最大程度降低了 OrderedDict 在數據存取時的開銷,雖付出了額外存儲空間,但仍維持了較好的存取性能。

有趣的細節

在閱讀 OrderedDict 實現時,我發現幾個有趣的細節。

1. 對 weakref 的使用

Python 語言的垃圾回收主要基于引用計數完成。引用計數算法簡單高效,但唯獨無法很好地處理“環形引用”。以下面這個場景舉例,在操作雙向鏈表時,向鏈表尾部插入新節點,需要:

  • 將新節點的下一個節點修改為根節點(link.next = root
  • 將根節點的上一個節點修改為新節點(link = root.prev

這將在 link 和 root 對象之間創建一個環形引用,二者都將使對方的引用計數加一,最終導致無法有效被 GC 及時回收。

介于此,OrderedDict 在處理類似情況時使用了 weakref[1] 模塊。相關代碼如下:

link.prev, link.next, link.key = last, root, key  # 1
last.next = link
root.prev = proxy(link)  # 2
  •  link 和 root 通過 link.next 建立了一個方向的引用關系;
  • root 和 link 再通過 root.prev 建立另一個方向的引用關系,但這次采用 proxy(...) 修飾了 link 對象,其中 proxy 來自于 weakref 模塊。

一旦對象被 weakref 模塊修飾過,引用它將不會觸發引用計數器的增長,這有效阻止了“環形引用”的產生,能讓 GC 更及時地回收內存。

2. 傳入 object() 作為默認值

同內置字典一樣,OrderdedDict 也需要支持 pop 操作。pop 方法負責從字典中“彈出”一個鍵(key)所對應的值,如果 key 不存在,返回調用方法時傳入的 default 默認值。

>>> d = {"a": 1}
>>> d.pop("a", 42)
1
>>> d.pop("c", 42)
42  # "c" 不存在,返回默認值 42

對于 OrderdedDict 而言,其在 pop 方法中,需要完成從自身字典中 pop 以及更新雙向鏈表兩件事。核心代碼如下:

class OrderedDict(dict):

    __marker = object()

    def pop(self, key, default=__marker):
        marker = self.__marker
        result = dict.pop(self, key, marker)
        if result is not marker:
            # The same as in __delitem__().
            # 更新鏈表部分已省略 ...

你可以注意到,在 dict.pop(self, key, marker) 中,代碼傳入了 marker 作為 key 不存在時的默認值。marker 并不是什么魔法對象,它僅僅只是類初始化時創建的一個小 object()

為什么選擇一個 object() 作為默認值?這是因為,此處需要通過 pop(...) 的返回值來嚴格區分“key 存在”和“key 不存在”兩種情況。所以,一個絕不可能在用戶字典中出現的新鮮熱乎的 object() 對象,是最為理想的默認值選擇。

引用鏈接

[1] weakref: https://docs.python.org/3/library/weakref.html

責任編輯:武曉燕 來源: piglei
相關推薦

2018-08-16 08:03:21

Python語言解釋器

2013-05-17 09:40:11

2020-08-02 22:54:04

Python編程語言開發

2021-12-21 06:09:05

Python切片索引

2020-05-13 09:03:14

Python開發代碼

2017-11-29 12:06:07

2019-03-11 08:36:11

Python代碼Flask

2012-06-18 14:51:09

Python

2020-07-28 00:48:54

Pythonpass語句開發

2020-07-22 07:55:12

Python開發函數

2020-08-09 18:01:26

Python開發源碼

2022-08-01 07:07:05

Python人工智能機器學習

2021-04-25 10:26:34

Python機器學習人工智能

2010-03-10 18:42:30

Python性能

2024-05-07 09:24:12

Python源碼Java

2020-08-10 15:48:01

Python輪子計算

2020-05-25 20:46:59

Python編程語言程序員

2017-03-25 21:32:40

Python編碼

2020-06-18 10:21:46

Python程序員技術

2021-03-03 11:38:16

Redis跳表集合
點贊
收藏

51CTO技術棧公眾號

日本a级片电影一区二区| 6080日韩午夜伦伦午夜伦| 精品国产免费人成电影在线观... 精品国产免费久久久久久尖叫 | 精品国产aaa| 欧美国产亚洲精品| 欧美日韩在线视频首页| 一区二区三区在线视频看| 亚洲欧美强伦一区二区| 奇米精品一区二区三区在线观看 | 日韩一区国产二区欧美三区| 亚洲美免无码中文字幕在线 | 亚洲蜜臀av乱码久久精品蜜桃| 国产视频一区二区不卡| 一二三区在线播放| 亚洲尤物影院| 欧美国产第一页| 538精品视频| 美女一区2区| 5566中文字幕一区二区电影| aa免费在线观看| 欧洲黄色一区| 中文字幕人成不卡一区| 精品人伦一区二区三区| 精品人妻伦一二三区久久| 日本sm残虐另类| 78色国产精品| 欧美精品色哟哟| 99精品一区| 在线免费观看羞羞视频一区二区| 中国一级特黄录像播放| 日韩中文字幕无砖| 欧美狂野另类xxxxoooo| 一本久道中文无码字幕av| 丰满大乳少妇在线观看网站| 中文字幕制服丝袜成人av| 欧美中文娱乐网| 神马精品久久| 不卡高清视频专区| 97人人做人人人难人人做| 一级全黄少妇性色生活片| 丝袜亚洲另类欧美| 日韩暖暖在线视频| 成年人视频在线免费看| 中文日韩在线| 57pao国产精品一区| 国产一级一片免费播放放a| 91欧美国产| 在线看日韩av| 999福利视频| 日本不卡免费一区| 日韩中文字幕在线免费观看| 超碰97av在线| 青青草91久久久久久久久| 在线看日韩欧美| 欧美乱大交做爰xxxⅹ小说| 四虎成人av| 毛片精品免费在线观看| 中文字幕手机在线观看| 国产精品vip| 久久久久久久久久久成人| 久久久久久久九九九九| 黄色成人在线网站| 午夜精品久久久久久久久久久久久 | 亚洲人妖av一区二区| 99re8这里只有精品| 97caopor国产在线视频| 亚洲一区在线视频| 僵尸世界大战2 在线播放| 超碰99在线| 色综合天天性综合| 91av视频免费观看| 日韩成人在线看| 亚洲激情视频在线| 手机免费看av| 最新国产精品久久久| 欧美精品18videos性欧| 久久久久久久久久久久久久av| 国产精品毛片在线| 国产精品免费一区豆花| 99久久免费国产精精品| 不卡av在线网| 日本黑人久久| av香蕉成人| 欧美色视频日本高清在线观看| 成年人在线观看视频免费| 亚洲影视资源| 日韩激情在线视频| 国产一区二区三区四区五区六区 | 国产一区二区在线不卡| 成人精品视频.| 欧美一区二区影视| 国产在线激情| 欧美日韩精品二区| 女人高潮一级片| 你懂的在线观看一区二区| 国产香蕉一区二区三区在线视频 | 中文字幕午夜精品一区二区三区| 久久久久久久一| 在线观看中文字幕网站| 粉嫩蜜臀av国产精品网站| 欧美精品一区二区三区在线四季 | 免费看男男www网站入口在线| 国产精品久久久久久久久果冻传媒| 日韩在线视频在线| 天堂久久午夜av| 亚洲国产美女精品久久久久∴| 老司机福利在线观看| 91久久在线| 国产美女久久精品| 外国精品视频在线观看 | 国产成人精品三级高清久久91| 日韩在线小视频| 日本三级免费看| 精品伊人久久久久7777人| 美女一区视频| 国模雨婷捆绑高清在线| 3d动漫精品啪啪1区2区免费| 免费在线观看污| 国产精品成人一区二区网站软件| 国产精品视频一区国模私拍| 日本国产在线| 一区二区三区四区高清精品免费观看| 亚洲精品乱码久久久久久自慰| 成人av激情人伦小说| 久久久国产精彩视频美女艺术照福利| 欧美日韩一二三四区| 成人精品免费看| 久久综合亚洲精品| 麻豆精品一区| 久久久www成人免费精品张筱雨 | 蜜臀av性久久久久蜜臀aⅴ流畅| 久久久久无码国产精品一区| 久久香蕉一区| 精品国一区二区三区| 欧美成人精品欧美一级| 日韩黄色一级片| 日本精品免费| 高清电影一区| 亚洲一级黄色av| 无码人妻av一区二区三区波多野 | 巨乳诱惑日韩免费av| 国内精品久久国产| 精品极品在线| 日韩电影第一页| 国产精品suv一区二区三区| 成人妖精视频yjsp地址| 男人天堂成人网| 国产一区二区三区黄网站| 欧美成人久久久| 99久久国产热无码精品免费| 亚洲精品欧美专区| 曰本三级日本三级日本三级| 国产精品mv在线观看| 91精品久久香蕉国产线看观看| 影院在线观看全集免费观看| 日韩欧美一区中文| 久久精品女人毛片国产| av电影一区二区| 日本毛片在线免费观看| 视频国产一区| 成人h猎奇视频网站| 最新国产在线拍揄自揄视频| 精品国产一区二区三区忘忧草 | 国产精品国产三级国产传播| 精品中文av资源站在线观看| 国风产精品一区二区| 国产精品国产| 日本久久久久久久久久久| 国产98在线| 欧美午夜精品久久久久久超碰| 熟女少妇内射日韩亚洲| 国产在线精品一区二区三区不卡| 国产91在线亚洲| 欧美一区二区三区久久| 国产精品∨欧美精品v日韩精品| 3d成人动漫在线| 91精品国产综合久久久久| www.av视频在线观看| 91视频你懂的| 中文字幕66页| 在线视频精品| 亚洲精品成人a8198a| 亚洲天堂网站| 97人人模人人爽人人喊中文字| 国产主播福利在线| 日韩一区二区三区四区五区六区| 日韩xxx高潮hd| 中文字幕av免费专区久久| 无码国产精品一区二区高潮| 亚洲资源av| 精品日韩在线播放| 国产欧美日韩| 福利视频一区二区三区| av在线不卡精品| 高清欧美电影在线| 91这里只有精品| 精品电影一区二区| 中国老头性行为xxxx| 亚洲亚洲人成综合网络| av网站免费在线看| 不卡在线观看av| 亚洲va在线va天堂va偷拍| 国产欧美一区二区色老头 | x88av在线| 成人免费电影视频| 天天看片天天操| 亚洲福利国产| 在线国产99| 久久99视频| 精品国产乱码久久久久软件| 国产成人免费av一区二区午夜| 日本一区二区在线免费播放| 久久香蕉一区| 欧美成人精品激情在线观看 | 欧美中文字幕在线视频| 亚洲奶水xxxx哺乳期| 精品亚洲一区二区三区在线观看| 一本一道精品欧美中文字幕| 在线视频一区二区三区| 91午夜视频在线观看| 亚洲三级免费观看| 性少妇bbw张开| 成人综合在线观看| 性久久久久久久久久久久久久| 日韩av一级片| 人妻丰满熟妇av无码区app| 在线亚洲自拍| 久久久亚洲国产精品| 综合久久一区| 免费看av软件| 国产精品久久天天影视| 色播五月综合| 区一区二视频| 亚洲国产一区在线| 欧美日韩国产一区二区三区不卡| 久久久久久亚洲精品不卡4k岛国| 久久男人av| 国产日韩一区二区三区| 给我免费播放日韩视频| 国产亚洲欧美一区二区| 精品资源在线| 国内精品二区| 一本色道久久综合亚洲精品酒店 | 91免费福利视频| 在线播放成人| 国产精品永久免费视频| 欧美美女福利视频| 91美女福利视频高清| 国产视频一区二| 成人免费在线一区二区三区| 91精品国产乱码久久久竹菊| 国产精品久久久久免费| 免费福利视频一区| 欧美一区二区三区四区夜夜大片 | 亚洲美免无码中文字幕在线| 国产精品丝袜xxxxxxx| 日韩免费高清在线| 麻豆中文一区二区| 国产精品99久久久精品无码| 成人福利在线看| 国产中年熟女高潮大集合| 国产精品国产三级国产专播品爱网 | 97在线视频精品| 超碰aⅴ人人做人人爽欧美| 国产成人福利视频| 在线高清欧美| 国产伦精品一区二区三区视频免费 | 欧美国产日韩在线观看成人| 亚洲综合激情另类小说区| 国产原创视频在线| 欧美色综合久久| 国产乱色精品成人免费视频| 精品黑人一区二区三区久久| 亚洲 欧美 激情 另类| 色狠狠久久aa北条麻妃| 久久大胆人体| 国产国产精品人在线视| 国产精品日韩精品在线播放| 国产精品成人观看视频免费| 亚洲三级精品| av中文字幕av| 日韩专区中文字幕一区二区| 亚洲一区二区福利视频| 成人免费毛片高清视频| 国产精品成人无码免费| 一区二区三区不卡在线观看| 欧美一区免费看| 8v天堂国产在线一区二区| 欧美一级一区二区三区| 中国china体内裑精亚洲片| 日韩影视在线| 国产精品美腿一区在线看| 一区二区日韩| 亚洲欧美精品在线观看| 99视频一区| 欧美激情国内自拍| 久久久不卡网国产精品一区| 欧美成人手机视频| 欧美色图片你懂的| 欧美 日韩 综合| 久久久精品影院| 日韩成人动漫| 狠狠色综合一区二区| 欧美国产一区二区三区激情无套| 欧美大片在线播放| 国产91精品在线观看| 亚洲黄色网址大全| 黑人巨大精品欧美一区免费视频 | 欧美精品在线看| 免费在线观看一区| 另类小说综合网| 国内精品美女在线观看| caoporm在线视频| 国产蜜臀av在线一区二区三区| 国产一级在线观看视频| 91精品国产综合久久久久久漫画| 蝌蚪视频在线播放| 91地址最新发布| av自拍一区| 狠狠精品干练久久久无码中文字幕 | 五月天亚洲婷婷| 精品国产区一区二| 精品国产自在精品国产浪潮| julia一区二区三区中文字幕| 久久国产精品高清| 亚洲高清不卡| 性久久久久久久久久久| 一区二区三区免费在线观看| 91在线视频国产| 日韩视频―中文字幕| 欧美不卡高清一区二区三区| 女人一区二区三区| 欧美一级二区| 一本色道久久综合亚洲精品图片| 亚洲成av人片www| 狠狠躁夜夜躁av无码中文幕| 久久国产精品电影| 久久av网站| 大荫蒂性生交片| 懂色av一区二区三区蜜臀| 久久久久久久9999| 精品免费一区二区三区| 国产网红在线观看| 国产日本一区二区三区| 在线综合欧美| 无码人妻aⅴ一区二区三区69岛| 色综合亚洲欧洲| 番号集在线观看| 国产欧美一区二区三区视频| 日韩精品一区二区三区免费观看| 向日葵污视频在线观看| 中文字幕一区在线观看视频| 97人妻一区二区精品免费视频| 久久深夜福利免费观看| 日韩一区二区三区色| 日本黄大片在线观看| 波多野结衣亚洲一区| 91video| 中文字幕亚洲欧美| 国产精品毛片无码| 日韩a∨精品日韩在线观看| 久久蜜桃av一区精品变态类天堂| 无码人妻一区二区三区线| 中文字幕精品av| 精品成人18| 日韩中文字幕三区| 国产精品色哟哟网站| 99精品在线看| 国产91ⅴ在线精品免费观看| 精品视频亚洲| 亚洲欧美日韩一二三区| 亚洲成人福利片| 成人精品一区二区三区免费 | 亚洲宅男天堂在线观看无病毒| 亚洲高清视频在线播放| 欧美最近摘花xxxx摘花| 欧美成免费一区二区视频| wwwxxx色| 欧美亚洲日本一区| 在线视频中文字幕第一页| 久久草视频在线看| 久久99精品国产.久久久久久| 精品爆乳一区二区三区无码av| 亚洲精品小视频| 国产免费区一区二区三视频免费| 久久成人免费观看| 国产精品二三区| 亚洲欧洲成人在线| 91九色综合久久| 久久久久欧美精品| 中文字幕在线2021| 国产视频欧美视频| 麻豆一二三区精品蜜桃| 国产裸体舞一区二区三区| 亚洲欧美另类久久久精品2019| 日中文字幕在线| 99国产超薄肉色丝袜交足的后果| 视频在线观看国产精品| 欧美精品xxxxx| www国产精品com|