为任意对象创建哈希?

时间:2013-04-22 22:29:50

标签: python

我一直在使用pickle.dumps来为任意Python对象创建哈希值,但是,我发现dict / set命令不是规范化的,因此结果是不可靠的。

SO和several上有related questions elsewhere,但我似乎无法找到使用相同基础进行相等的哈希算法({{ 1}} / __getstate__结果)。我理解滚动自己的基本要求,但显然我更喜欢使用经过测试的东西。

这样的图书馆存在吗?我想我实际要求的是一个确定性地序列化对象的库(使用__dict____getstate__),以便我可以对输出进行散列。

修改

为了澄清,我正在寻找与Python的hash(或__hash__)返回的值不同的东西。我想要的本质上是任意对象的校验和,可能是也可能不是。该值应根据对象的状态而变化。 (我使用“状态”来指代由__dict__重新调整的字典,或者,如果不存在,则指向对象的__getstate__。)

2 个答案:

答案 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()