Поведение `==` и `is` в Python: почему печатается "compare" один раз
@python_quizРазберем этот квиз
Условие (код):

Кратко: при выполнении этого кода сначала вызывается __eq__, который печатает compare и возвращает True, затем проверяется идентичность оператором is, которая тоже даёт True. В результате в консоли вы увидите строку compare, а затем True True.
Разберём детально.
Что делает каждый элемент кода
__eq__(self, other)— метод экземпляра, вызываемый при сравнении через==. В данном случае он печатаетcompareи возвращаетTrue.w == w— вызываетw.__eq__(w). Даже если объект сравнивается сам с собой, метод будет вызван, если он определён.w is w— проверяет идентичность объектов (тот же объект в памяти). Для одного и того же переменногоwэто всегдаTrue.print(w == w, w is w)— перед тем, как печатать результат, Python вычисляет аргументы слева направо: сначалаw == w, затемw is w. Полученные значения передаются вprint, который выводит их через пробел.
Пошаговое выполнение
- Вычисляется
w == w:
- Вызывается Weird.__eq__, печатается compare.
- __eq__ возвращает True.
- Вычисляется
w is w:
- Оператор is проверяет идентичность — True.
printполучает два аргумента(True, True)и выводит:True True.
Ожидаемый вывод в консоли:

Или, если показать выполнение в коде:

Вывод:

Анализ возможных вариантов ответа (описания из квиза)
- "Выведет: compare затем 'True True'": соответствует поведению кода —
__eq__вызывается и печатает один раз, затемprintвыводит два булевых значения. - "Выведет: compare затем 'True False'": неверно, потому что
w is wдля одного и того же объекта всегдаTrue. - "Выведет: compare compare затем 'True True'": неверно в данном случае —
__eq__вызывается только один раз при вычисленииw == w. Чтобы увидеть два вызова, нужно было бы дважды выполнять сравнение==(например, в двух разных выражениях). - "Выведет: ничего, так как == не вызывается для одного и того же объекта": неверно — наличие определённого
__eq__заставляет его вызываться даже при сравнении объекта с самим собой.
Дополнительные замечания и подводные камни
- Если метод
__eq__возвращаетNotImplemented, тогда интерпретатор попробует обратную операцию или вернётFalseв зависимости от ситуации. В нашем примере метод возвращает явноеTrue, поэтому поведение однозначно. - Порядок вычисления аргументов функций в Python гарантирован — слева направо. Это важно, если в выражениях есть побочные эффекты (как в нашем
print). - Для встроенных неизменяемых типов (например, чисел) поведение оператора
==может быть оптимизировано, но для пользовательских классов управление остаётся за методами сравнения, которые вы определяете.
Вывод
Определение __eq__ влияет на поведение оператора == даже при сравнении объекта с самим собой — метод будет вызван и может иметь побочные эффекты. Оператор is проверяет идентичность и для одного и того же объекта вернёт True. В примере вывод будет: сначала строка compare (от печати в __eq__), затем True True.