【问题标题】:Pickle serialization order mystery泡菜序列化顺序之谜
【发布时间】:2014-04-14 20:36:46
【问题描述】:

2017 年 6 月 8 日更新

虽然 3 年过去了,但我的 PR 仍然作为临时解决方案通过执行输出命令等待处理。 Stream-Framework 可能会重新考虑使用内容作为通知键的设计。 GitHub Issue #153 引用了这个。

问题

参见以下示例:

import pickle
x = {'order_number': 'X', 'deal_url': 'J'}

pickle.dumps(x)
pickle.dumps(pickle.loads(pickle.dumps(x)))
pickle.dumps(pickle.loads(pickle.dumps(pickle.loads(pickle.dumps(x)))))

结果:

(dp0\nS'deal_url'\np1\nS'J'\np2\nsS'order_number'\np3\nS'X'\np4\ns.
(dp0\nS'order_number'\np1\nS'X'\np2\nsS'deal_url'\np3\nS'J'\np4\ns.
(dp0\nS'deal_url'\np1\nS'J'\np2\nsS'order_number'\np3\nS'X'\np4\ns.

显然,每次转储的序列化输出都会发生变化。当我从任何键中删除一个字符时,这不会发生。我发现这是 Stream-Framework 使用腌制输出作为在其 k/v 存储上存储通知的关键。如果我们更好地了解这里发生的事情,我会提出请求。我找到了两种解决方案来防止它:

A - 排序后转换为字典(是的,以某种方式提供预期的副作用)

import operator
sorted_x = dict(sorted(x.iteritems(), key=operator.itemgetter(1)))

B - 删除下划线(但不确定这是否总是有效)

那么是什么导致了pickle字典排序下的谜团?

证明在 dict 上调用 sort 会提供转储以产生相同的结果:

import operator
x = dict(sorted(x.iteritems(), key=operator.itemgetter(1)))

pickle.dumps(x)
"(dp0\nS'order_number'\np1\nS'X'\np2\nsS'deal_url'\np3\nS'J'\np4\ns."

x = pickle.loads(pickle.dumps(x))
x = dict(sorted(x.iteritems(), key=operator.itemgetter(1)))

pickle.dumps(x)
"(dp0\nS'order_number'\np1\nS'X'\np2\nsS'deal_url'\np3\nS'J'\np4\ns."

【问题讨论】:

  • dict 不保持键的顺序。您应该考虑使用来自collectionsOrderedDict
  • 这并不神秘。字典是无序的。
  • 在定义上我同意,但如果我在每次加载后应用解决方案 A,转储会神奇地产生相同的结果。所以泡菜在某种程度上受到内存顺序或其他东西的影响。
  • 所以你宁愿想出一种方法来意外地按照你想要的方式对字典进行排序,而不是切换到保持顺序的数据结构?
  • 你有没有注意到用你选择的键调用dict(sorted(x.iteritems()))总是会导致一个可能的字典顺序?关键是无关紧要的,因为操作没有意义。没有区别。如果您在任何真实环境中信任它,您将有一个糟糕的时间。您的测试数据集还包含一个带有两个键的字典。用几千个试试,看看效果如何。

标签: python dictionary serialization pickle stream-framework


【解决方案1】:

字典是未排序的数据结构。这意味着顺序是任意的,pickle 将按原样存储它们。如果要使用排序字典,可以使用collections.OrderedDict

当您在解释器中玩耍时,您认为您看到的任何顺序只是解释器与您相处融洽。

来自dict的文档:

最好将字典视为一组无序的键:值对,并要求键是唯一的(在一个字典中)

请记住,函数 dict.keys()dict.values()dict.items() 也会以任意顺序返回它们各自的值。

【讨论】:

  • 你意识到你调用pickle.loads(dictionary_pickle)的那一刻你构造了一个具有任意顺序的字典,不管pickle如何存储字典的顺序?
  • 您提供的解决方案 A 在对iteritems() 的结果进行排序后创建了一个字典,实际上失去了顺序。
  • 而且它仍然解决了问题 :) 我同意 pickle 有权选择自己的演示文稿,但我强迫它相同,只是添加了质疑的证据。
  • 给定dict 的顺序可能在每次运行时都相同假设输入法相同并且使用相同版本的 Python。您的数据只是强化了这一点。
猜你喜欢
  • 2018-09-17
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
相关资源
最近更新 更多