is vs == и кэширование малых целых в Python

is vs == и кэширование малых целых в Python

@python_quiz

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

Код, который рассматриваем:

python

Краткий результат выполнения: программа выведет True True. Ниже — почему так происходит и какие нюансы стоит иметь в виду.

Что проверяют is и ==

  • is — проверяет тождественность объектов, то есть указывают ли две переменные на один и тот же объект в памяти.
  • == — проверяет равенство значений, вызывает метод сравнения объектов (для чисел сравнивает численные значения).

Поэтому is и == могут вести себя по-разному: две переменные могут иметь равные по значению объекты (== True), но быть разными объектами в памяти (is False).

Почему для 256 получается True True

В CPython существует пул (кэш) для небольших целых чисел (обычно диапазон от -5 до 256 включительно). Это сделано ради оптимизации: для этих значений заранее выделяются объекты, и все ссылки на такие числа в коде могут указывать на один и тот же объект.

В примере выше и a, и b ссылаются на один объект, представляющий число 256, поэтому:

  • a is b → True (один объект),
  • a == b → True (значения равны).

Демонстрация и сравнение с другим числом

Посмотрим примеры, которые наглядно показывают поведение:

python

Замечания:

  • На практике поведение с числами вне кэша (например, 257) может зависеть от контекста (интерактивный REPL, байткод-компиляция, оптимизации объединения констант). Иногда компилятор может объединить одинаковые литералы в коде, и is для больших литералов окажется True. Поэтому такие наблюдения не являются надёжным инструментом для проверки равенства.

Анализ вариантов (логика выбора)

Варианты вывода могли быть такие (перечисляем логически):

  • "False False": это означало бы, что объекты разные и значения разные — не соответствует факту, т.к. значения одинаковы.
  • "False True": здесь объекты разные, но значения равны — возможно для больших чисел вне кэша, но не для 256 в стандартной сборке CPython.
  • "True False": объекты одинаковы, но значения разные — невозможно: если это один объект числа, его значение не может одновременно быть другим.
  • "True True": объекты совпадают и значения равны — именно то, что наблюдается для 256 в типичных сборках CPython благодаря кэшу малых целых.

Практическое правило

  • Для сравнения значений всегда используйте ==.
  • Оператор is применяйте только для проверки идентичности объектов, например, x is None.
  • Не полагайтесь на поведение is для чисел — оно зависит от реализации и оптимизаций.

Итог

В рассматриваемом примере и is, и == дают True из-за механизма кэширования малых целых в CPython: обе переменные указывают на один и тот же объект с числом 256. Однако это поведение специфично для реализации и не заменяет семантику == для проверки равенства значений.

Report Page