6

我需要创建一个从我自己的自定义类(从 dict 派生)的对象到另一个自定义类的对象的映射。在我看来,有两种方法可以做到这一点:

  1. 我可以使对象可散列。我不确定我会怎么做。我知道我可以实现__hash__(),但我不确定如何实际计算哈希(应该是一个整数)。

  2. 由于可以比较我的对象,我可以创建一个列表 [(myobj, myotherobj)],然后实现查找查找元组中第一项与查找键相同的元组。实现这一点很简单(对象的数量很少),但如果标准库中已经存在类似的东西,我想避免重新发明轮子。

在我看来,想要查找 unhashables 将是一个常见问题,所以我假设有人已经解决了这个问题。关于如何__hash()__为类似dict的对象实现的任何建议,或者是否有其他一些标准方法来制作不可散列的查找表?

4

4 回答 4

3

以可变对象作为键的映射通常很困难。这真的是你想要的吗?如果您认为您的对象是不可变的(在 Python 中没有真正强制执行不变性的方法),或者您知道它们在用作映射中的键时不会被更改,您可以为它们实现自己的哈希函数几种方式。例如,如果您的对象只有可散列的数据成员,您可以返回所有数据成员的元组的散列作为对象散列。

如果您的对象是类似字典的,您可以使用所有键值对的冻结集的哈希。

def __hash__(self):
    return hash(frozenset(self.iteritems()))

这仅在所有值都是可散列的情况下才有效。为了保存哈希的重新计算(每次查找都会完成),您可以缓存哈希值并在设置了一些脏标志时重新计算它。

于 2010-12-16T15:16:35.387 回答
2

一个简单的解决方案似乎是做lookup[id(myobj)] = myotherobj而不是lookup[myobj] = myotherobj. 对这种方法有什么评论吗?

于 2010-12-16T15:38:40.893 回答
1

如果您没有在自定义类中存储任何其他不可散列的对象,则以下内容应该有效:

def __hash__(self):
    return hash(self.items())
于 2010-12-16T15:11:36.633 回答
1

这是 a 的实现frozendict,取自http://code.activestate.com/recipes/414283/

class frozendict(dict):
    def _blocked_attribute(obj):
        raise AttributeError, "A frozendict cannot be modified."
    _blocked_attribute = property(_blocked_attribute)

    __delitem__ = __setitem__ = clear = _blocked_attribute
    pop = popitem = setdefault = update = _blocked_attribute

    def __new__(cls, *args):
        new = dict.__new__(cls)
        dict.__init__(new, *args)
        return new

    def __init__(self, *args):
        pass

    def __hash__(self):
        try:
            return self._cached_hash
        except AttributeError:
            h = self._cached_hash = hash(tuple(sorted(self.items())))
            return h

    def __repr__(self):
        return "frozendict(%s)" % dict.__repr__(self)

我会替换tuple(sorted(self.items()))frozenset(self.iteritems())Spacecowboy的回答。并考虑加入__slots__ = ("_cached_hash",)课堂。

于 2010-12-16T15:35:42.643 回答