Когда вы пишете:
a == b
Python спрашивает у объектов: «Вы представляете одно и то же значение?» — и вызывает под капотом метод __eq__. Поэтому:
два разных списка [1, 2] и [1, 2] равны по значению;
две разные строки "hi" и "hi" равны по содержимому и т.п.
Когда вы пишете:
a is b
Python вообще не смотрит на содержимое, он сравнивает адреса объектов: «эти переменные указывают на один и тот же объект в памяти или нет?». Пример:
x = [1, 2, 3]
y = [1, 2, 3]
z = x
x == y # True (значения совпадают)
x is y # False (разные объекты)
x is z # True (это один и тот же объект)
[x == y → True, x is y → False] — классика для собеседований.
Почему is нельзя использовать вместо ==?
Иногда is «случайно» даёт True при сравнении чисел или коротких строк — из‑за кеширования и интернирования объектов в CPython. Это деталь реализации, а не гарантированное поведение.
a = 256
b = 256
a is b # часто True, но на это нельзя опираться
a = 257
b = 257
a is b # может быть False
Для сравнения чисел, строк, списков, словарей и т.д. используем ==. is применяем там, где важно, один ли это объект — чаще всего это проверки is None и работа с синглтонами.
Когда использовать каждый оператор?
Практическое правило для собеседования: == — когда сравниваем значения (числа, строки, структуры данных),
if status == "ok":
...
а is — при проверке на None и синглтоны:
if value is None:
...
В одной фразе: == — «равны ли по смыслу», is — «это точно один и тот же объект?».