【问题标题】:How to implement __cmp__() and __hash__() for my class?如何为我的班级实现 __cmp__() 和 __hash__()?
【发布时间】:2015-02-11 04:46:57
【问题描述】:

我想编写一个可以用作可散列集合中的键的类(例如在dict 中)。我知道默认情况下用户类是可散列的,但在这里使用 id(self) 是错误的。

我的班级持有一个tuple 作为成员变量。从tuple 派生似乎不是一个选项,因为在我的构造函数中,我没有得到与tuple 构造函数相同类型的参数。但也许这不是限制?

我需要的基本上是 tuple 的哈希值,就像一个真正的元组给出的那样。

hash(self.member_tuple) 就是这样做的。

这里的想法是两个元组可以相等,但 id 不相等。

如果我按如下方式实现我的__cmp__()

def __cmp__(self, other):
    return cmp(self, other)

这会自动诉诸hash(self) 进行比较吗? ...或者我应该按如下方式实现它:

def __cmp__(self, other):
    return cmp(self.member_tuple, other)

我的__hash__()函数被实现为返回持有的tuple的哈希值,即:

def __hash__(self):
    return hash(self.member_tuple)

基本上,__cmp__()__hash__() 是如何交互的?我不知道__cmp__() 中的other 是否已经是一个散列,以及我是否应该与“我的”散列(这将是持有的tuple 之一)或self 进行比较。

那么哪一个是正确的呢?

任何人都可以对此有所了解并可能指出我的文档吗?

【问题讨论】:

    标签: python dictionary hash collections python-2.x


    【解决方案1】:

    我不会使用__cmp__,而是坚持使用__eq__。对于散列就足够了,您不想在这里扩展到可排序。此外,__cmp__ 已从 Python 3 中删除,以支持丰富的比较方法(__eq____lt____gt__ 等)。

    接下来,当成员元组相等时,您的 __eq__ 应该返回 True:

    def __eq__(self, other):
        if not isinstance(other, ThisClass):
            return NotImplemented
        return self.member_tuple == other.member_tuple
    

    other 对象的类型不同时返回NotImplemented 单例是一种好习惯,因为这会将相等性测试委托给other 对象;如果它没有实现__eq__ 或者还返回NotImplemented,P​​ython 将回退到标准的id() 测试。

    您的__hash__ 实施非常到位。

    因为哈希并不意味着是唯一的(它只是在哈希表中选择一个槽的一种方法),然后使用相等来确定匹配的键是否已经存在或是否发生了哈希冲突。因此,如果对象被散列到的槽为空,则不会调用 __eq__(或 __cmp__,如果缺少 __eq__)。

    这确实意味着如果两个对象被认为相等(a.__eq__(b) 返回True),那么它们的哈希值也必须相等。否则你可能会得到一个损坏的字典,因为 Python 将不再能够确定一个键是否已经存在于哈希表中。

    如果您的__eq____hash__ 方法都将它们的职责委托给self.member_tuple 属性,则您正在维护该属性;你可以相信基本的tuple 类型已经正确实现了这一点。

    请参阅 glossary definition of hashableobject.__hash__() documentation。如果你好奇,我已经写过dictset 类型在内部是如何工作的:

    【讨论】:

    • 谢谢。不过,最后一段让我感到困惑。如何保证哈希值相同?我可以假设在散列tuple 时?我不可能知道任何其他给定 tuple 的哈希是否与成员元组的哈希相同,可以吗?
    • @0xC0000022L:您将哈希函数委托给元组,就像委托相等测试一样,因此您可以很好地维护该属性。如果元组曾经开始产生不同的哈希值,即使对于相等的元组,那将是一个更大的问题,您可以放心非常及时修复。
    猜你喜欢
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    • 2012-10-05
    • 2020-10-11
    • 2017-12-23
    • 1970-01-01
    相关资源
    最近更新 更多