我正在编写一个持久化到磁盘的映射类。我目前只允许str
键,但如果我可以使用更多类型会很好:希望达到任何可散列的(即与 builtin 相同的要求dict
),但更合理的是我会接受字符串、unicode、int 和这些类型的元组。
为此,我想推导出一个确定性的序列化方案。
选项 1 - 酸洗密钥
我的第一个想法是使用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."
是否有任何实现/协议组合pickle
对于某些类型是确定性的(例如,只能cPickle
与协议 0 一起使用)?
选项 2 - Repr 和 ast.literal_eval
另一种选择是使用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))
这种方法的问题是它repr
本身是否对我在这里允许的类型具有确定性。我相信由于 str/unicode 文字的变化,这将无法在 2/3 版本障碍中幸存下来。这也不适用于2**32 - 1 < x < 2**64
在 32 位和 64 位平台之间跳转的整数。是否有任何其他条件(即字符串在同一个解释器中的不同条件下是否以不同的方式序列化)?编辑:我只是想了解它崩溃的条件,不一定要克服它们。
选项 3:自定义代表
另一个可能过大的选择是编写我自己的repr
,它可以消除我知道(或怀疑可能)有问题的 repr 的事情。我只是在这里写了一个例子:http: //gist.github.com/423945
(如果这一切都失败了,那么我可以将键的散列与键和值的泡菜一起存储,然后遍历具有匹配散列的行,以寻找与预期键无关的行,但这确实很复杂其他一些事情,我宁愿不这样做。编辑: 事实证明,内置hash
函数也不是跨平台的确定性。从头开始。)
有什么见解吗?