is или ==: тождество против равенства и кеш малых int

Очень частый каверзный вопрос: чем is отличается от == и почему is иногда «врёт» на числах.

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

Вопрос: в чём разница и когда что использовать?

Чёткий ответ. == — для сравнения значений (почти всегда именно это вам нужно). is — только для сравнения с синглтонами: x is None, x is True, x is False. Сравнивать через is числа и строки — ошибка, даже если иногда «работает».

a = [1, 2, 3]
b = [1, 2, 3]
print("a == b:", a == b)   # значения равны
print("a is b:", a is b)   # но это разные объекты
c = a
print("a is c:", a is c)   # c — то же самое имя того же объекта

Вывод:

a == b: True
a is b: False
a is c: True

Ловушка: кеш малых целых чисел

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

a = int("256")
b = int("256")
print("256 is 256:", a is b)   # в кеше

c = int("257")
d = int("257")
print("257 is 257:", c is d)   # вне кеша — разные объекты

print("значения равны:", c == d)

Вывод:

256 is 256: True
257 is 257: False
значения равны: True

Здесь int("256") заставляет создать число во время выполнения. Видно: 256 попадает в кеш и оба имени указывают на один объект, а 257 — нет. Если бы мы сравнивали через ==, результат был бы предсказуем всегда.

Правило для собеседования

Сравниваем сОператор
None, True, Falseis / is not
числа, строки, списки, объекты — по значению==
«это буквально тот же объект?»is
x = None
print(x is None)        # правильная проверка на None
value = 0
print(value == 0)       # сравнение значения
print(value is None)    # 0 — это не None

Вывод:

True
True
False

Итог

  • == — равенство значений; is — тождество объектов (один id).
  • is используйте только с None/True/False.
  • Кеш малых int (−5..256) делает is на числах обманчивым — не полагайтесь на него.
Проверьте себя
1. Что сравнивает оператор is?
AЗначения объектов
BТождество — один ли это объект в памяти
CТипы объектов
DДлину объектов
2. Для чего рекомендуется использовать is?
AДля сравнения чисел
BДля сравнения строк
CДля проверки на None/True/False
DВсегда вместо ==
3. Почему int("257") is int("257") даёт False?
A257 — нечётное
B257 вне диапазона кеша малых int (−5..256)
Cis не работает с int
DЭто баг Python
Поддержать проект