序列化过程是确定性的吗?
使用Pickle时,对于相同的输入值,它的输出总是一样的吗?我想可能会有一些问题,特别是当我们对字典进行序列化时,即使它们的内容相同,但插入和删除的历史不同,输出可能会不一样。我的目标是利用Pickle和SHA1来创建一个函数参数的“签名”,以便实现缓存功能。
2 个回答
0
你说的“相同的输出”是什么意思呢?通常来说,进行一次完整的过程(也就是把数据保存起来再读取出来)时,应该总是能得到相同的结果。不过,我觉得在不同的情况下,保存的数据格式本身不一定会完全一样。比如在不同的平台上,这种情况是有可能发生变化的。
在你程序的一次运行中,使用这种数据保存的方法来记忆结果是没问题的。我自己也用过几次,没遇到什么麻烦,但那都是一些比较简单的问题。有一个问题是,这种方法并不能覆盖所有有用的情况(比如函数:你不能直接保存函数,所以如果你的函数需要一个可以调用的参数,那就不行了)。
11
我想说,当你在处理字典的时候,如果它们的内容相同但插入和删除的历史不同,可能会有一些意想不到的问题。
对的:
>>> pickle.dumps({1: 0, 9: 0}) == pickle.dumps({9: 0, 1: 0})
False
另请参见:pickle.dumps不适合用于哈希
我的目标是使用Pickle和SHA1为函数参数创建一个“签名”,以便实现记忆化。
这其中有很多根本性的问题。要找到一个能正确映射相等性的对象到字符串的转换几乎是不可能的——想想对象身份的问题:
>>> a = object()
>>> b = object()
>>> a == b
False
>>> pickle.dumps(b) == pickle.dumps(a)
True
根据你的具体需求,你可能能够将对象层次结构转换成可以进行哈希处理的形式:
def hashablize(obj):
"""Convert a container hierarchy into one that can be hashed.
Don't use this with recursive structures!
Also, this won't be useful if you pass dictionaries with
keys that don't have a total order.
Actually, maybe you're best off not using this function at all."""
try:
hash(obj)
except TypeError:
if isinstance(obj, dict):
return tuple((k, hashablize(v)) for (k, v) in sorted(obj.iteritems()))
elif hasattr(obj, '__iter__'):
return tuple(hashablize(o) for o in obj)
else:
raise TypeError("Can't hashablize object of type %r" % type(obj))
else:
return obj