Python 3.6和Python 3.5中的字典顺序之间的差异

时间:2019-05-13 12:44:51

标签: python dictionary unordered

我试图了解python 3.6.7python 3.5.2中python字典之间的区别。他们存储键值对顺序的方式似乎有所不同。

例如,假设有一个名为di的字典:

    di = {'a':1,'A':1,'b':2, 'B':2, 'c':3, 'C':3}

Python 3.5.2中,当我打印di时,输出为:

    {'C': 3, 'a': 1, 'A': 1, 'B': 2, 'c': 3, 'b': 2}

但是,在Python 3.6.7中是:

    {'a': 1, 'A': 1, 'b': 2, 'B': 2, 'c': 3, 'C': 3}

两个版本之间有哪些更改? 如何使我的代码对python 3.6.7的结果进行排序,使其类似于3.5.2的结果。

P.S。我知道Python字典中实际上没有无订单。这里的术语order用于使读者易于理解我的问题。 谢谢。

2 个答案:

答案 0 :(得分:3)

“允许”字典的顺序对于程序的每次运行都不同,更不用说版本了。在每个版本上始终按顺序订购只有CPython知道的实现细节 *的事实。您的程序不应依赖此行为。

  

如何使我的代码对python 3.6.7的结果进行排序(类似于3.5.2的结果)。

使用OrderedDict

*实际上,as of Python 3.7中,保留插入顺序正式是语言规范的一部分。

答案 1 :(得分:3)

TLDR:

要复制基于散列的排序,必须采用显式排序的dict并强加自己的排序。

from collections import OrderedDict

def cpy35dict(source_dict):
    """Apply hash-ordering to a dictionary"""
    return OrderedDict(  # ensure stable ordering
        sorted(          # order items by key hash
            source_dict.items(),
            key=lambda item: hash(item[0])
        )
    )

这将复制CPython直至Python 3.5中使用的顺序。 请注意,Python语言规范对Python 3.7之前的订单不提供 no 保证-如果您坚持订购,则还应在Python 3.5和更早版本中使用此保证。


dict类容器基本上有三种类型的订单:

  • 无订单:商品没有特定的订单。每次访问都可能返回不同的顺序。
  • 特定订单:商品有明确定义的订单。每次访问都返回相同的顺序。
  • 任意顺序:未定义顺序。它可能会或可能不会使用特定的顺序。

根据Python规范,dict具有任意顺序(最高至Python 3.6)和插入顺序(自Python 3.7起)。

  

在3.7版中进行了更改:保证字典顺序为插入顺序。此行为是3.6版CPython的实现细节。 [Mapping Types — dict¶]

但是,任意顺序并不排除特定顺序。它的基本含义是“无论实现感觉如何”。不同的实现使用不同的方案来实现dict

  • PyPy自Python 2.7/3.2

  • 开始使用插入顺序
  • CPython 3.5-使用基础哈希函数的顺序。由于几种类型都有加盐的哈希,这意味着您每次调用都会获得不同的顺序。

  • CPython 3.6使用插入项目的顺序。这显然是实现细节。

  

此新实现的顺序保留方面被认为是实现细节,不应依赖于[What's new in Python 3.6]

换句话说,Python 3.6和更早版本的代码应该对dict的顺序做出 no 假设。仅适用于Python 3.7和更高版本的代码应假设dict的顺序。