字典在Python 3.6中排序(至少在CPython实现下),与之前的版本不同 . 这似乎是一个重大变化,但它只是documentation中的一个短段 . 它被描述为CPython实现细节而不是语言特性,但也暗示这可能成为未来的标准 .
在保留元素顺序的同时,新字典实现如何比旧字典执行得更好?
以下是文档中的文字:
dict()现在使用PyPy开创的“紧凑”表示 . 与Python 3.5相比,新dict()的内存使用量减少了20%到25% . PEP 468(保留函数中** kwargs的顺序 . )由此实现 . 这个新实现的顺序保留方面被认为是一个实现细节,不应该依赖(这可能会在未来发生变化,但是在更改语言规范之前,希望在几种版本的语言中使用这个新的dict实现为所有当前和未来的Python实现强制命令保留语义;这也有助于保持与随机迭代顺序仍然有效的语言的旧版本的向后兼容性,例如Python 3.5) . (由INADA Naoki在issue 27350中提供 . 最初由Raymond Hettinger提出的想法 . )
2017年12月更新:对于Python 3.7, dict
s保留插入顺序为guaranteed
3 回答
以下是回答原始的第一个问题:
我认为文档中的这句话实际上足以回答你的问题
dict
并未明确指定为有序集合,因此如果您希望保持一致并且不依赖于新实现的副作用,则应该坚持使用OrderedDict
.让您的代码面向未来:)
有关于here的辩论 .
编辑: Python 3.7 will keep this as a feature see
他们是 insertion ordered [1] . 从Python 3.6开始,对于Python的CPython实现,字典记住了插入项的顺序 . 这被认为是Python 3.6中的实现细节;如果你想要在其他Python实现(和其他有序行为[1])中保证插入排序,你需要使用
OrderedDict
.As of Python 3.7 ,这不再是实现细节,而是成为语言功能 . From a python-dev message by GvR:
这只是意味着你可以依赖它 . Python的其他实现还必须提供插入有序字典,如果他们希望成为Python 3.7的一致性实现 .
基本上,通过保留两个数组 .
第一个数组dk_entries按照插入顺序保存字典的条目(of type PyDictKeyEntry) . 保留顺序是通过这是一个仅附加数组来实现的,其中总是在末尾插入新项目(插入顺序) .
第二个dk_indices,保存
dk_entries
数组的索引(即表示dk_entries
中相应条目位置的值) . 此数组充当哈希表 . 当一个键被散列时,它会导致存储在dk_indices
中的一个索引,并通过索引dk_entries
来获取相应的条目 . 由于只保留索引,因此该数组的类型取决于字典的整体大小(范围从int8_t(1
字节)到int32_t / int64_t(4
/8
字节)32
/64
位构建)在前面的实现中,必须分配类型为
PyDictKeyEntry
且大小为dk_size
的稀疏数组;不幸的是,它也导致了很多空的空间,因为该数组不允许超过2/3 * dk_size
完整for performance reasons . (而空的空间仍然有PyDictKeyEntry
大小!) .现在情况并非如此,因为只存储了所需的条目(已插入的条目)和类型为
intX_t
的稀疏数组(X
,具体取决于字典大小)2/3 * dk_size
已满 . 空白区域从类型PyDictKeyEntry
更改为intX_t
.因此,显然,创建一个类型为
PyDictKeyEntry
的稀疏数组比用于存储int
的稀疏数组要多得多 .如果感兴趣,你可以看到有关此功能的完整对话on Python-Dev,这是一个很好的阅读 .
In the original proposal made by Raymond Hettinger,可以看到所使用的数据结构的可视化,其捕获了该想法的要点 .
正如您现在可以看到的那样,在原始提案中,大量空间基本上是空的,以减少碰撞并使查找更快 . 使用新方法,您可以通过在索引中移动实际需要的稀疏性来减少所需的内存 .
[1]:我说“插入有序”而不是“有序”,因为存在OrderedDict,“ordered”表示dict对象不提供的进一步行为 . OrderedDicts是可逆的,提供顺序敏感的方法,主要提供顺序敏感的相等测试(==,!=) . dicts目前不提供任何这些行为/方法 .
[2]:新的字典实现通过更紧凑的设计实现更好的内存;这是主要的好处 . 速度方面,差异并不是那么激烈,新的字典可能会引入轻微的回归(例如键查找),而在其他情况下(迭代和调整大小)会出现性能提升 .
总的来说,字典的性能,特别是在现实生活中,由于引入的紧凑性而得到改善 .
更新:Guido van Rossum announced on the mailing list,从Python 3.7
dict
开始,所有Python实现都必须保留插入顺序 .