is vs == и кэширование малых целых в Python
@python_quizРазберем этот квиз
Код, который рассматриваем:

Краткий результат выполнения: программа выведет True True. Ниже — почему так происходит и какие нюансы стоит иметь в виду.
Что проверяют is и ==
is— проверяет тождественность объектов, то есть указывают ли две переменные на один и тот же объект в памяти.==— проверяет равенство значений, вызывает метод сравнения объектов (для чисел сравнивает численные значения).
Поэтому is и == могут вести себя по-разному: две переменные могут иметь равные по значению объекты (== True), но быть разными объектами в памяти (is False).
Почему для 256 получается True True
В CPython существует пул (кэш) для небольших целых чисел (обычно диапазон от -5 до 256 включительно). Это сделано ради оптимизации: для этих значений заранее выделяются объекты, и все ссылки на такие числа в коде могут указывать на один и тот же объект.
В примере выше и a, и b ссылаются на один объект, представляющий число 256, поэтому:
a is b→ True (один объект),a == b→ True (значения равны).
Демонстрация и сравнение с другим числом
Посмотрим примеры, которые наглядно показывают поведение:

Замечания:
- На практике поведение с числами вне кэша (например, 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. Однако это поведение специфично для реализации и не заменяет семантику == для проверки равенства значений.