推荐实现__eq__和__hash__的方式

23

Python 文档 提到,如果您重载 __eq__ 并且对象是不可变的,则应该同时重载 __hash__,以使类能够正确地进行哈希。

在实践中,当我这样做时,我经常会得到像下面这样的代码:

class MyClass(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __eq__(self, other):
        if type(other) is type(self):
            return (self.a == other.a) and (self.b == other.b)
        else:
            return False

    def __hash__(self):
        return hash((self.a, self.b))

这段内容有些重复,而且很容易忘记在更新一个时更新另一个。

是否有推荐的方法来同时实现这些方法?

3个回答

33

回答自己的问题。似乎执行此操作的一种方法是定义一个辅助的__members函数,并在定义__hash____eq__时使用它。这样,就不会有重复:

class MyClass(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __members(self):
        return (self.a, self.b)

    def __eq__(self, other):
        if type(other) is type(self):
            return self.__members() == other.__members()
        else:
            return False

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

4
这里存在风险,即self.aself.b的改变会导致哈希值发生变化(这将破坏各种操作)。 - raylu
@raylu,你能再解释一下吗? - jossefaz
one = MyClass(1, 1); stuff = {one}; print(one in stuff); print(MyClass(2, 2) in stuff); one.a = one.b = 2; print(MyClass(2, 2) in stuff); print(MyClass(2, 2) in list(stuff))this prints True, False, False, True. (2, 2) is "not" in the set stuff but it's in list(stuff), which doesn't use __hash__ - raylu
此处所述,可以使用vars(self)self.__dict__代替手动定义self.__members。但请注意,它们都返回可变且不可哈希的字典。要使用具有__hash__的字典,请查看此答案的末尾:hash(tuple(sorted(self.__dict__.items()))) - Matt Popovich

-1

这是否等价于这个一行代码的eq操作符?

   def __eq__(self, other):
       return type(other) is type(self) and (self.a == other.a) and (self.b == other.b)

-3

我认为你可以使用用户定义的哈希函数更好。

class MyClass(object):

def __init__(self, a, b):
    self.a = a
    self.b = b

def __eq__(self, other):
    if type(other) is type(self):
        return (self.a, self.b) == (other.a, other.b)
    else:
        return NotImplemented

def __hash__(self):
    return hash((self.a, self.b))

1
这会导致错误的结果,例如 MyClass(2, -2) == MyClass(-2, 2),因为在 CPython 中存在哈希碰撞。您永远不应该使用 hash(a) == hash(b) 来判断 ab 是否相等。 - kaya3
是的,这是我的错。我修复了代码。 - tiantanshu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接