Поведение `==` и `is` в Python: почему печатается "compare" один раз

Поведение `==` и `is` в Python: почему печатается "compare" один раз

@python_quiz

Разберем этот квиз

Условие (код):

python

Кратко: при выполнении этого кода сначала вызывается __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, который выводит их через пробел.

Пошаговое выполнение

  1. Вычисляется w == w:

- Вызывается Weird.__eq__, печатается compare.
- __eq__ возвращает True.

  1. Вычисляется w is w:

- Оператор is проверяет идентичность — True.

  1. print получает два аргумента (True, True) и выводит: True True.

Ожидаемый вывод в консоли:

text

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

python

Вывод:

text

Анализ возможных вариантов ответа (описания из квиза)

  • "Выведет: 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.

Report Page