История вопроса:
В Python сравнение объектов по значению происходит через оператор '==', который под капотом вызывает метод eq. Поведение этого метода по умолчанию наследуется от object, и сравнивает идентичность объектов (для большинства классов).
Проблема:
Когда мы хотим, чтобы экземпляры пользовательских классов сравнивались осмысленно (например, два разных объекта Person с одинаковым набором данных считались равными), стандартное поведение недостаточно — требуется явно определить, как происходит сравнение.
Решение:
Для изменения поведения '==' необходимо переопределить метод eq в собственном классе. Если класс должен быть хешируемым, потребуется также переопределить hash.
Пример кода:
class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True
Ключевые особенности:
Является ли сравнение '==' всегда симметричным для объектов разных типов?
Не обязательно — если первый объект возвращает NotImplemented, вызывается обратное сравнение. Иначе может быть асимметрией.
class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False
Если не реализовать eq, как будут сравниваться объекты одного пользовательского класса?
Будет сравниваться id (идентичность в памяти, а не значения атрибутов).
class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False
Можно ли определять eq без hash для объектов, которые должны быть ключами словаря?
Нет. Если eq изменён, hash тоже желательно определить, иначе объект станет не хешируемым (TypeError при использовании как ключа).
class Foo: def __eq__(self, other): return True # hash наследуется от object, но поведение будет непредсказуемым # Лучше явно задать __hash__
Негативный кейс
При проектировании класса ValueObject в коллективе не учли, что реализовали только eq, но не hash. При попытке использовать объект как ключ в словаре или элемент множества, возникало исключение TypeError.
Плюсы:
Быстрое внедрение пользовательского сравнения.
Минусы:
Невозможность использовать объекты во множествах и словарях, сложность в отладке.
Позитивный кейс
В другом проекте разработчики явно реализовали оба метода — eq и hash, строго следуя правилу: если два объекта равны по eq, их хэши совпадают.
Плюсы:
Корректная работа хеш-структур, консистентное поведение, простота в сопровождении.
Минусы:
Потеря гибкости: равные по значениям объекты неразличимы в hash-контейнерах.