Какой магический метод переопределяется для изменения поведения объекта при сравнении в Python
Что проверяют
Ответ «__eq__» дают почти все. Проверяют, знаете ли вы весь набор методов богатого сравнения, что делает NotImplemented и что происходит с хешированием после переопределения __eq__. Следом часто просят объяснить, почему объект вдруг нельзя положить в set.
Как отвечать
За каждый оператор отвечает свой метод:
__eq__и__ne__:==и!=.__ne__писать обычно не нужно: по умолчанию он вызывает__eq__и инвертирует результат;__lt__,__le__,__gt__,__ge__:<,<=,>,>=. Сортировка черезsorted()иlist.sort()использует только__lt__;NotImplemented: возвращается, когда метод не умеет сравнивать с объектом такого типа. Тогда Python пробует отражённый метод второго операнда: дляa < bэтоb.__gt__(a). Если отказались оба,==откатывается к сравнению идентичности, а<бросаетTypeError. Возвращать вместо этогоFalseнеправильно, так ломается сравнение с чужими типами;__hash__: если в классе определён__eq__без__hash__, Python ставит__hash__ = None, и объект становится нехешируемым. Для неизменяемого объекта определите__hash__по тем же полям, что участвуют в__eq__.
Покажите, что знаете инструменты, которые избавляют от ручной работы. functools.total_ordering достраивает недостающие методы порядка по __eq__ и одному из __lt__, __le__, __gt__, __ge__. @dataclass по умолчанию генерирует __eq__ по полям, order=True добавляет сравнения порядка, а frozen=True вместе с eq=True даёт и __hash__.
Метода __cmp__ в Python 3 нет, его убрали вместе со встроенной функцией cmp.
Где спотыкаются
Переопределяют __eq__ и получают TypeError: unhashable type при попытке положить объект в set или сделать ключом словаря.
Сравнивают поля без проверки типа: обращение к other.name у объекта другого класса падает с AttributeError, хотя правильный ответ здесь NotImplemented.
Считают __hash__ по изменяемым полям. Объект меняется после вставки в set, хеш становится другим, и найти его там уже нельзя.