我一直在使用pickle.dumps
来为任意Python对象创建哈希值,但是,我发现dict / set命令不是规范化的,因此结果是不可靠的。
SO和several上有related questions elsewhere,但我似乎无法找到使用相同基础进行相等的哈希算法({{ 1}} / __getstate__
结果)。我理解滚动自己的基本要求,但显然我更喜欢使用经过测试的东西。
这样的图书馆存在吗?我想我实际要求的是一个确定性地序列化对象的库(使用__dict__
和__getstate__
),以便我可以对输出进行散列。
修改
为了澄清,我正在寻找与Python的hash
(或__hash__
)返回的值不同的东西。我想要的本质上是任意对象的校验和,可能是也可能不是。该值应根据对象的状态而变化。 (我使用“状态”来指代由__dict__
重新调整的字典,或者,如果不存在,则指向对象的__getstate__
。)
答案 0 :(得分:1)
在我看来,Pickler可以被扩展并且选择函数被覆盖以规范化必要的类型,这就是我正在做的事情。这是它的样子:
from copy import copy
from pickle import Pickler, MARK, DICT
from types import DictionaryType
class CanonicalizingPickler(Pickler):
dispatch = copy(Pickler.dispatch)
def save_set(self, obj):
rv = obj.__reduce_ex__(0)
rv = (rv[0], (sorted(rv[1][0]),), rv[2])
self.save_reduce(obj=obj, *rv)
dispatch[set] = save_set
def save_dict(self, obj):
write = self.write
write(MARK + DICT)
self.memoize(obj)
self._batch_setitems(sorted(obj.iteritems()))
dispatch[DictionaryType] = save_dict
答案 1 :(得分:0)
我会假设一旦你计算(并存储)它们的哈希值,你就会把你的对象视为不可变的。否则,你应该非常小心你正在做的事情(例如,不应该使用他们的可靠性质量将它们存储在集合,dicts等中。)
也就是说,最优雅的方法是首先将对象的__dict__
中的所有成员存储在可混合类型中。而不是list
,而是使用元组(当然是可以使用的对象)。而不是dict
s,使用this问题的任何解决方案作为你的hashable-dict类型(我个人使用@ alex's)。同样,键和值都必须是可清除的才能使其正常工作。
然后,您的__hash__
方法可以使用您正在使用的相同hashable-dict,例如:
def _hashable_state(self):
return MyHashableDict(self.__dict__)
def __hash__(self):
return hash(self._hashable_state())
def __reduce__(self):
return self._hashable_state()