Are dictionaries ordered in Python 3.6+?
字典在python 3.6中排序(至少在cpython实现下),与以前的版本不同。这似乎是一个实质性的变化,但它只是文档中的一小段。它被描述为一个cpython实现细节,而不是一个语言特性,但也意味着这可能成为未来的标准。
在保持元素顺序的同时,新的字典实现如何比旧的实现执行得更好?
以下是文档中的文本:
dict() now uses a"compact" representation pioneered by PyPy. The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5. PEP 468 (Preserving the order of **kwargs in a function.) is implemented by this. The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5). (Contributed by INADA Naoki in issue 27350. Idea originally suggested by Raymond Hettinger.)
号
更新日期:2017年12月:保证为python 3.7提供
Are dictionaries ordered in Python 3.6+?
号
它们是按插入顺序排列的[1]。从python 3.6开始,对于python的cpython实现,字典记住插入项的顺序。在Python3.6中,这被视为一个实现细节;如果您希望在其他Python实现中保证插入顺序(以及其他顺序行为[1]),则需要使用
从Python3.7开始,这不再是一个实现细节,而是一个语言特性。来自gvr的python dev消息:
Make it so."Dict keeps insertion order" is the ruling. Thanks!
号
这就意味着你可以依靠它。如果希望成为python 3.7的一致实现,python的其他实现还必须提供插入顺序字典。
How does the Python
3.6 dictionary implementation perform better[2] than the older one while preserving element order?
号
基本上,通过保留两个数组。
第一个数组,
dk_entries 按照插入的顺序保存字典的条目(PyDictKeyEntry 类型)。保留顺序是通过将新项始终插入末尾(插入顺序)的仅附加数组来实现的。第二个是
dk_indices 持有dk_entries 数组的索引(即表示dk_entries 中相应条目位置的值)。此数组用作哈希表。当一个键被散列时,它会导致存储在dk_indices 中的一个索引,并通过索引dk_entries 获取相应的条目。由于只保留索引,因此该数组的类型取决于字典的总体大小(从int8_t 型(1 字节)到int32_t /int64_t 型(4 /8 字节)在32 /64 位构建上的范围)。
在以前的实现中,必须分配一个类型为
现在情况并非如此,因为只存储所需的条目(已插入的条目),并保留一个类型为
因此,显然,创建类型为
您可以在python dev上看到关于这个特性的完整对话,如果您感兴趣,这是一个很好的阅读。
在RaymondHettinger最初提出的建议中,可以看到所使用的数据结构的可视化,它抓住了这个想法的要点。
For example, the dictionary:
1 d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}is currently stored as:
1
2
3
4
5
6
7
8 entries = [['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']]Instead, the data should be organized as follows:
1
2
3
4 indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
号
正如您现在看到的,在最初的建议中,很多空间基本上是空的,以减少碰撞并使查找更快。使用新方法,您可以通过移动索引中真正需要的稀疏度来减少所需的内存。
下面是第一个原始问题的答案:
Should I use
dict orOrderedDict in Python 3.6?
号
我认为文档中的这句话实际上足以回答你的问题
The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon
号
使您的代码成为未来的证据:)
这里有一个争论。
编辑:python 3.7将保留这一特性,请参见
更新:guido van rossum在邮件列表中宣布,从python 3.7