is vs == и поведение целых чисел в Python

is vs == и поведение целых чисел в Python

@python_quiz

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

Коротко: код проверяет идентичность и равенство чисел. Результат может выглядеть неожиданно из‑за особенностей кэша малых целых и оптимизаций компилятора.

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

python

Что делает этот код:

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

Разбор вывода — почему так

  1. Малые целые в CPython кэшируются. По умолчанию интервал кэшируемых int — от -5 до 256 включительно. Поэтому литералы 256 обычно ссылаются на один и тот же объект, и a is b даёт True.
  1. Литерал 257 выходит за пределы стандартного кэша, но здесь встречается интересный нюанс: когда одинаковые константы встречаются в одном модуле/функции, компилятор CPython может объединять (share) эти константы при компиляции (peephole optimizer / constant folding / constant pooling). В данном примере литерал 257 используется и при присваивании, и в выражении сравнения — компилятор может сделать так, что это один объект в таблице констант кода. Поэтому c is 257 может тоже вернуть True.
  1. c == 257 — сравнение по значению, всегда True, если число равно 257.

Важно: объединение констант и детали кэширования — внутренняя реализация CPython. Их поведение не гарантируется спецификацией языка и может зависеть от версии интерпретатора и контекста (файл, модуль, REPL, оптимизации).

Демонстрации и контрпримеры

Оригинальный фрагмент (в одной строке/модуле) часто даёт такой вывод:

python

Но если создать значение 257 во время выполнения (а не как литерал в коде), идентичность обычно нарушится:

python

Ещё пример показывающий, что поведение зависит от способа получения значения:

python

Замечание: некоторые выражения, например 200 + 57, тоже могут быть вычислены на этапе компиляции (и тогда будут едиными константами). Чтобы гарантированно получить новый объект для больших чисел, используйте динамичное создание (например, int() от строки или результат вычислений, зависящих от пользовательского ввода).

Практические выводы и рекомендации

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

Если нужно — можно привести дополнительные эксперименты с разными версиями Python или результатами в REPL vs в скрипте, чтобы увидеть, как именно конкретный интерпретатор ведёт себя в вашей среде.

Report Page