字典在Python 3.6+中是有序的吗?
它们的插入顺序是[1]。
从Python 3.6开始,对于Python的CPython实现,字典会记住插入项的顺序。这被认为是Python 3.6中的实现细节;你需要使用OrderedDict,如果你想在其他Python实现(和其他有序行为[1])之间保证插入顺序。
从Python 3.7开始,这是一个有保证的语言特性,而不仅仅是一个实现细节。来自GvR的python-dev消息:
让它成为现实。“词典保持插入顺序”是裁决。谢谢!
这仅仅意味着您可以依赖它。Python的其他实现如果希望成为符合Python 3.7的实现,也必须提供一个插入顺序字典。
Python 3.6字典实现如何在保持元素顺序的同时比旧的[2]执行得更好?
本质上,通过保持两个数组。
The first array, dk_entries, holds the entries (of type PyDictKeyEntry) for the dictionary in the order that they were inserted. Preserving order is achieved by this being an append only array where new items are always inserted at the end (insertion order).
The second, dk_indices, holds the indices for the dk_entries array (that is, values that indicate the position of the corresponding entry in dk_entries). This array acts as the hash table. When a key is hashed it leads to one of the indices stored in dk_indices and the corresponding entry is fetched by indexing dk_entries. Since only indices are kept, the type of this array depends on the overall size of the dictionary (ranging from type int8_t(1 byte) to int32_t/int64_t (4/8 bytes) on 32/64 bit builds)
在之前的实现中,必须分配类型为PyDictKeyEntry和大小为dk_size的稀疏数组;不幸的是,由于性能原因,该数组不允许超过2/3 * dk_size,因此也导致了大量的空白空间。(空的空间仍然有PyDictKeyEntry大小!)。
现在不是这样了,因为只存储了必需的条目(那些已经插入的),并且保留了类型为intX_t (X取决于字典大小)2/3 * dk_sizes full的稀疏数组。空格类型从PyDictKeyEntry变为intX_t。
因此,显然,创建PyDictKeyEntry类型的稀疏数组比存储int类型的稀疏数组需要更多的内存。
如果感兴趣,你可以在Python-Dev上看到关于这个特性的完整对话,这是一本不错的读物。
在Raymond Hettinger最初提出的建议中,可以看到所使用的数据结构的可视化,这抓住了想法的要点。
For example, the dictionary:
d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
is currently stored as [keyhash, key, value]:
entries = [['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']]
Instead, the data should be organized as follows:
indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
正如您现在可以直观地看到的,在最初的方案中,许多空间基本上是空的,以减少冲突并使查找更快。使用新方法,您可以通过将稀疏性移到真正需要的位置(即索引中)来减少所需的内存。
[1]:我说“插入有序”,而不是“有序”,因为OrderedDict的存在,“有序”暗示了‘dict’对象*不提供*的进一步行为。OrderedDicts是可逆的,提供顺序敏感的方法,主要是提供顺序敏感的相等性测试(' == ',' != ')。“字典目前没有提供任何这些行为/方法。
[2]:新的字典实现执行更好的**内存明智**设计更紧凑;这是主要的好处。在速度方面,差异并不是那么大,在某些地方,新字典可能会引入轻微的回归(例如键查找),而在其他地方(想到迭代和调整大小),性能应该会有所提升。
总的来说,由于引入了紧凑性,字典的性能得到了提高,特别是在现实生活中。