在Python中腌制字典

d-d*_*d-d 6 python pickle python-2.7

我可以期望同一个pickled dict的字符串表示在同一个Python版本的不同机器/运行中是一致的吗?在同一台机器上运行的范围?

例如

# Python 2.7

import pickle
initial = pickle.dumps({'a': 1, 'b': 2})
for _ in xrange(1000**2):
    assert pickle.dumps({'a': 1, 'b': 2}) == initial
Run Code Online (Sandbox Code Playgroud)

它取决于我的dict对象的实际结构(嵌套值等)吗?

UPD:问题是 - 无论我的dict对象是什么样的(什么键/值等),我实际上无法在一次运行(Python 2.7)的范围内使上面的代码失败

Mar*_*ers 7

您不能在一般情况下,出于同样的原因,您不能在其他情况下依赖字典顺序这里的酸洗并不特别。字典的字符串表示是当前字典迭代顺序的函数,无论您如何加载它。

您自己的小测试太有限了,因为它不会对测试字典进行任何更改,也不会使用会导致冲突的键。您使用完全相同的 Python 源代码创建字典,因此它们将产生相同的输出顺序,因为字典的编辑历史完全相同,并且使用 ASCII 字符集中的连续字母的两个单字符键不太可能造成碰撞。

并不是您实际上测试字符串表示是否相等,您只测试它们的内容是否相同(字符串表示不同的两个字典仍然可以相等,因为相同的键值对,受到不同的插入顺序,可以生成不同的字典输出顺序)。

接下来,cPython 3.6 之前的字典迭代顺序中最重要的因素是哈希键生成函数,它必须在单个 Python 可执行生命周期内保持稳定(否则你会破坏所有字典),因此单进程测试永远不会根据不同的哈希函数结果查看字典顺序变化。

目前,所有酸洗协议修订版都将字典的数据存储为键值对流;加载时,流被解码,键值对按磁盘顺序分配回字典,因此从这个角度来看,插入顺序至少是稳定的。但是在不同的 Python 版本、机器架构和本地配置之间,哈希函数结果绝对会有所不同:

  • PYTHONHASHSEED环境变量,在用于散列的生成中使用strbytesdatetime密钥。该设置从 Python 2.6.8 和 3.2.3 开始可用,random从 Python 3.3 开始默认启用并设置为。因此设置因 Python 版本而异,并且可以在本地设置为不同的内容。
  • 哈希函数产生一个ssize_t整数,一种依赖于平台的有符号整数类型,所以不同的架构可以产生不同的哈希,因为它们使用更大或更小的ssize_t类型定义。

由于机器与机器之间以及 Python 运行与 Python 运行之间的哈希函数输出不同,您看到字典的不同字符串表示形式。

最后,从 cPython 3.6 开始,dict类型的实现更改为更紧凑的格式,也恰好保留了插入顺序。从 Python 3.7 开始,语言规范已更改为强制执行此行为,因此其他 Python 实现必须实现相同的语义。因此,在 Python 3.7 之前的不同 Python 实现或版本之间进行酸洗和取消酸洗也会导致不同的字典输出顺序,即使所有其他因素都相同。