为任意对象创建哈希?

2024-06-06 10:51:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在使用pickle.dumps为任意Python对象创建散列,但是,我发现dict/set顺序没有规范化,因此结果不可靠。在

在SO和elsewhere上有severalrelatedquestions,但我似乎找不到一个哈希算法,它使用相同的等式基础(__getstate__/__dict__结果)。我了解自己滚动的基本要求,但显然我更喜欢使用经过测试的东西。在

这样的图书馆存在吗?我想我实际需要的是一个库,它确定地序列化对象(使用__getstate____dict__),这样我就可以散列输出。在

编辑

为了澄清这一点,我在寻找与Python的^{}(或^{})返回的值不同的东西。我想要的基本上是一个任意对象的校验和,它可能是也可能不是散列的。此值应根据对象的状态而变化。(我使用“state”指的是__getstate__返回的dict,如果不存在,则是对象的__dict__。)


Tags: 对象算法so图书馆顺序规范化基础pickle
2条回答

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

也就是说,最优雅的方法是首先将对象的__dict__中的所有成员存储为散列类型。不用lists,使用元组(当然是散列对象)。不要使用dicts,而是使用this问题的任何解决方案作为散列dict类型(我个人使用的是@alex)。同样,键和值都必须是散列的,这样才能工作。在

然后,您的__hash__方法可以使用与您使用的相同的散列dict,例如:

def _hashable_state(self):
    return MyHashableDict(self.__dict__)
def __hash__(self):
    return hash(self._hashable_state())
def __reduce__(self):
    return self._hashable_state()

我突然想到,Pickler可以被扩展,select函数也可以被重写以规范化必要的类型,所以这就是我要做的。下面是它的样子:

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

相关问题 更多 >