Mik*_*ers 5 python serialization pickle
我正在编写一个持久化到磁盘的映射类。我目前只允许使用str键,但如果我可以使用更多类型,那就太好了:希望可以达到任何可散列的类型(即与 builtin 相同的要求dict),但更合理的是我会接受 string、unicode、int 和这些类型的元组。
为此,我想推导出一个确定性的序列化方案。
我的第一个想法是使用 pickle(或 cPickle)模块来序列化密钥,但我注意到来自pickle和的输出cPickle彼此不匹配:
>>> import pickle
>>> import cPickle
>>> def dumps(x):
... print repr(pickle.dumps(x))
... print repr(cPickle.dumps(x))
...
>>> dumps(1)
'I1\n.'
'I1\n.'
>>> dumps('hello')
"S'hello'\np0\n."
"S'hello'\np1\n."
>>> dumps((1, 2, 'hello'))
"(I1\nI2\nS'hello'\np0\ntp1\n."
"(I1\nI2\nS'hello'\np1\ntp2\n."
Run Code Online (Sandbox Code Playgroud)
是否有任何实现/协议组合pickle对于某些类型集是确定性的(例如只能cPickle与协议 0 一起使用)?
另一种选择是用于repr转储和ast.literal_eval加载。我编写了一个函数来确定给定的键是否可以在这个过程中存活(它允许的类型相当保守):
def is_reprable_key(key):
return type(key) in (int, str, unicode) or (type(key) == tuple and all(
is_reprable_key(x) for x in key))
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是它repr本身对于我在这里允许的类型是否具有确定性。我相信由于 str/unicode 文字的变化,这不会在 2/3 版本障碍中幸存下来。这也不适用于2**32 - 1 < x < 2**64在 32 位和 64 位平台之间跳转的整数。是否有任何其他条件(即字符串在同一个解释器中的不同条件下以不同的方式序列化)?编辑:我只是想了解这打破的条件,不一定要克服它们。
另一个可能有点矫枉过正的选择是自己写repr,它使我知道(或怀疑可能是)有问题的 repr 变得平坦。我刚刚在这里写了一个例子:http : //gist.github.com/423945
(如果这一切都失败了,那么我可以将键的散列与键和值的 pickle 一起存储,然后遍历具有匹配散列的行,寻找对预期键进行解压的行,但这确实很复杂其他一些事情,我宁愿不这样做。编辑: 事实证明,内置hash函数也不是跨平台的确定性的。从头开始。)
任何见解?
在阅读了基本类型的 repr 实现的大部分源代码(CPython 2.6.5)后,我得出结论(有合理的信心)这些repr类型实际上是确定性的。但坦率地说,这是预料之中的。
我相信该repr方法很容易受到几乎所有相同情况的影响,在这些情况下该marshal方法会崩溃(longs > 2**32 永远不可能是int32 位机器上的 an ,不保证不会在版本或解释器之间更改等) 。
我暂时的解决方案是使用该repr方法并编写一个全面的测试套件以确保repr在我使用的各种平台上返回相同的值。
从长远来看,自定义 repr 函数将消除所有平台/实现差异,但对于手头的项目来说肯定是大材小用。不过,我将来可能会这样做。
| 归档时间: |
|
| 查看次数: |
1205 次 |
| 最近记录: |