7

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

在 SO 和其他地方几个 相关的 问题,但我似乎找不到使用相同基础的哈希算法(/结果)。我了解自己滚动的基本要求,但显然我更喜欢使用经过测试的东西。__getstate____dict__

有这样的图书馆吗?我想我实际上要的是一个确定性地序列化对象的库(使用__getstate__and __dict__),以便我可以散列输出。

编辑

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

4

2 回答 2

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
于 2013-05-30T01:51:10.563 回答
0

我假设一旦计算(并存储)了对象的哈希值,您就会将对象视为不可变的。否则,你应该对你正在做的事情非常小心(例如,不应该使用它们的散列性质量来将它们存储在集合、字典等中)。

也就是说,最优雅的方法是首先将对象中的所有成员存储__dict__在可散列类型中。而不是lists,使用元组(当然是可散列的对象)。而不是dicts,使用这个问题的任何解决方案作为你的 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()
于 2013-04-23T05:41:43.780 回答