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

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

@python_quiz

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

Код, который требуется проанализировать:

python

Коротко: вывод этого кода — True False True. Ниже объясню почему, разберу смысл операторов и покажу варианты с демонстрацией.

Что делают is и ==

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

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

Кеширование целых в CPython

Реализация CPython хранит в кэше маленькие целые числа в диапазоне примерно от -5 до 256. Это значит, что для этих значений создаётся один объект, и ссылки на него переиспользуются. По этой причине любые две переменные, содержащие одно и то же маленькое целое, будут указывать на один объект — и выражение с is вернёт True.

Диапазон кеша — поведение CPython, это реализация, а не универсальное свойство языка Python.

Разбор примера

  • a = b = 256 — обе переменные получают ссылку на один объект с числом 256. Поэтому a is b → True.
  • c = 257 — объект с 257 обычно не кэшируется, поэтому c указывает на отдельный объект с этим значением.
  • c is 257 — поскольку литерал 257 в данном контексте чаще создаёт отдельный объект, сравнение тождественности обычно даёт False.
  • c == 257 — сравнение значений, очевидно, True.

Итоговый вывод:

python

Анализ всех вариантов (логика)

Предложенные ответы представляли возможные комбинации трёх логических выражений: (a is b), (c is 257), (c == 257). Объяснение для каждой позиции:

  • Первая позиция (a is b): для 256 это True из-за кеша.
  • Вторая позиция (c is 257): для 257 обычно False (отдельный объект).
  • Третья позиция (c == 257): всегда True, так как значения совпадают.

Поэтому комбинация True False True — соответствует поведению CPython в типичном случае.

Демонстрация и нюансы

Иногда компилятор может оптимизировать литералы в одном кодовом объекте, и поведение с is для больших чисел может выглядеть по-разному в отдельных окружениях. Чтобы надёжно продемонстрировать, что объекты с числом 257 различны, можно создавать их в рантайме (например, через int()):

python

Еще демонстрация id() для визуального подтверждения:

python

Замечание: в интерактивной сессии или при оптимизациях компилятора поведение с повторяющимися литералами может отличаться, поэтому опираться на is для чисел нельзя.

Выводы и рекомендации

  • is — для проверки идентичности объектов (например, проверка на None: x is None).
  • == — для сравнения значений, использовать его для чисел и строк.
  • CPython кеширует целые в диапазоне примерно [-5, 256], поэтому сравнения на is для этих значений могут быть True.
  • Не полагайтесь на is для определения равенства чисел — это ошибка стиля и потенциальный источник багов.

Report Page