python字典与顺序有关吗_python – 为什么在字典和集合中的顺序是任意的?
順序不是任意的,而是取決于字典或集合的插入和刪除歷史,以及特定的Python實現。對于這個答案的其余部分,對于’dictionary’,你還可以讀取’set’;集合被實現為僅具有鍵且沒有值的字典。
鍵被哈希,哈希值被分配到動態表中的插槽(它可以根據需要增長或縮小)。并且該映射過程可能導致沖突,意味著鍵將必須基于已經存在的在下一個時隙中被插槽。
列出插槽上的內容循環,因此鍵按照它們當前駐留在表中的順序列出。
例如,取鍵’foo’和’bar’,并假設表大小為8個插槽。在Python 2.7中,hash(‘foo’)是-4177197833195190597,hash(‘bar’)是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實現)是hash table,使用開放尋址。如果你好奇,并理解C足夠好,看看C implementation所有(詳細記錄)的細節。你也可以觀看這個Pycon 2010 presentation by Brandon Rhodes關于CPython dict如何工作,或拿起一份Beautiful Code的副本,其中包括由安德魯·庫奇林執行的一章。
注意,從Python 3.3開始,使用隨機散列種子,使得哈希沖突不可預測,以防止某些類型的拒絕服務(其中攻擊者通過引起大量散列沖突來使得Python服務器無響應)。這意味著給定字典的順序也依賴于當前Python調用的隨機散列種子。
其他實現可以為字典自由使用不同的結構,只要它們滿足為他們編寫的Python接口,但我相信迄今為止的所有實現使用了散列表的變體。
Python 3.6引入了一個新的dict實現,維護插入順序,并且啟動速度更快,內存效率更高。不是保留大的稀疏表,其中每行引用存儲的散列值,以及鍵和值對象,新實現添加一個較小的散列數組,只引用稠密表中的索引(一個只包含與實際鍵值對),并且是按順序列出包含的項目的密集表。
Python 2.7和更新版本還提供了一個OrderedDict class,dict的子類,添加了一個額外的數據結構來記錄密鑰順序。以一些速度和額外的內存為代價,這個類記住了你按什么順序插入密鑰;列表項,值或項將按照該順序進行。它使用存儲在附加字典中的雙向鏈表來有效地保持訂單的最新。參見post by Raymond Hettinger outlining the idea.注意,集合類型仍然是無序的。
如果你想要一個有序集,你可以安裝oset package;它適用于Python 2.5及以上。
總結
以上是生活随笔為你收集整理的python字典与顺序有关吗_python – 为什么在字典和集合中的顺序是任意的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 对象的交互_Java中什么是对
- 下一篇: Python变量使用前必须先声明,并且一