Рекомендуемый способ реализации __eq__ и __hash__

В документации 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))

Это несколько повторяется, и есть явный риск забыть обновить одно при обновлении другого.

Есть ли рекомендуемый способ реализации этих методов вместе?


person Jonas Adler    schedule 18.07.2017    source источник


Ответы (2)


Отвечая на мой собственный вопрос. Кажется, один из способов сделать это — определить вспомогательную функцию __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())
person Jonas Adler    schedule 18.07.2017
comment
здесь есть риск того, что self.a или self.b изменится, что приведет к изменению хэша (что нарушит все виды вещей) - person raylu; 10.12.2019

Это эквивалент этого однострочного eq?

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