python字典和集合双向索引_Python-为什么字典和集合中的顺序是任意的?
小編典典
順序不是任意的,而是取決于字典或集合的插入和刪除歷史,以及特定的Python實現。對于這個答案的其余部分,對于"dictionary",你還可以讀取"set";set被實現為只有鍵而沒有值的字典
對鍵進行散列,并將散列值分配給動態表中的插槽(它可以根據需要增長或收縮)。映射過程可能導致沖突,這意味著必須根據已存在的鍵將密鑰插入下一個插槽。
列出內容循環遍歷插槽,因此鍵以它們當前在表中的順序列出。
以鍵'foo'和'bar'為例,假設表的大小為8個插槽。在Python 2.7中,hash('foo')is -4177197833195190597,hash('bar')is 327024216814240868。模數8,這意味著這兩個鍵分別插入插槽3和4中,然后:
>>> hash('foo')
-4177197833195190597
>>> hash('foo') % 8
3
>>> hash('bar')
327024216814240868
>>> hash('bar') % 8
4
這通知了他們的上市順序:
>>> {'bar': None, 'foo': None}
{'foo': None, 'bar': None}
除3和4之外的所有插槽均為空,在表上循環時首先列出插槽3,然后列出插槽4,因此’foo’在之前列出’bar’。
bar和baz,但是散列值恰好相距8,因此映射到完全相同的插槽4:
>>> hash('bar')
327024216814240868
>>> hash('baz')
327024216814240876
>>> hash('bar') % 8
4
>>> hash('baz') % 8
4
現在,他們的順序取決于首先插入哪個密鑰。第二個密鑰將必須移至下一個插槽:
>>> {'baz': None, 'bar': None}
{'bar': None, 'baz': None}
>>> {'bar': None, 'baz': None}
{'baz': None, 'bar': None}
此處的表順序有所不同,因為一個或另一個鍵先插入插槽。
CPython使用的基礎結構(最常用的Python實現)的技術名稱是哈希表,該哈希表使用開放式尋址。如果你感到好奇,并且對C足夠了解,請查看C實現的所有(詳細記錄)細節。你還可以觀看Brandon Rhodes在Pycon 2010上所作的有關CPython如何dict工作的演示,或者獲取Beautiful Code的副本,其中包括Andrew Kuchling撰寫的有關實現的章節。
請注意,從Python 3.3開始,還使用了隨機的哈希種子,從而使哈希沖突無法預測,以防止某些類型的拒絕服務(攻擊者通過引起大量哈希沖突而使Python服務器無響應)。這意味著給定字典的順序也取決于當前Python調用的隨機哈希種子。
其他實現可以自由地為字典使用不同的結構,只要它們滿足已記錄的Python接口,但我相信到目前為止,所有實現都使用哈希表的變體。
CPython 3.6引入了一個新的 dict實現,該實現可以維護插入順序,并且啟動起來更快,內存效率更高。新的實現沒有保留一個大的稀疏表,其中的每一行都引用了存儲的哈希值以及鍵和值對象,而是添加了一個較小的哈希數組,該數組僅引用密集表中的索引(一個索引僅包含實際行數鍵值對),而密集表恰好按順序列出了包含的項。有關更多詳細信息,請參見Python-Dev的建議。請注意,在Python 3.6中,這被認為是實現細節,Python語言不指定其他實現必須保留順序。這在Python 3.7中有所更改,其中的詳細信息是提升為語言規范 ; 為了使任何實現與Python 3.7或更高版本正確兼容,必須復制此保留順序的行為。
Python 2.7及更高版本還提供了一個OrderedDict類,該類的子類dict添加了額外的數據結構來記錄鍵順序。以某種速度和額外的內存為代價,此類會記住你按什么順序插入鍵。然后列出鍵,值或項目將按此順序進行。它使用存儲在其他詞典中的雙向鏈接列表來使訂單保持最新狀態。請參閱Raymond Hettinger的帖子,概述該想法。請注意,該set類型仍然是無序的。
如果你需要訂購的套裝,則可以安裝oset軟件包;它適用于Python 2.5及更高版本。
2020-02-05
總結
以上是生活随笔為你收集整理的python字典和集合双向索引_Python-为什么字典和集合中的顺序是任意的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python输入框_selenium+p
- 下一篇: 征信概念股票龙头一览表,2022征信相关