Ответ
Оператор ==
сравнивает значения объектов (равенство), в то время как is
проверяет, ссылаются ли две переменные на один и тот же объект в памяти (идентичность).
a == b
эквивалентно вызовуa.__eq__(b)
. Проверяет, равны ли значения.a is b
эквивалентноid(a) == id(b)
. Проверяет, являются лиa
иb
одним и тем же объектом.
Пример
# Списки - изменяемые объекты
list_a = [1, 2, 3]
list_b = list_a # b теперь ссылается на тот же объект, что и a
list_c = [1, 2, 3] # c - это новый объект с таким же значением
print(f"list_a == list_b: {list_a == list_b}") # True: значения равны
print(f"list_a is list_b: {list_a is list_b}") # True: один и тот же объект
print(f"list_a == list_c: {list_a == list_c}") # True: значения равны
print(f"list_a is list_c: {list_a is list_c}") # False: разные объекты в памяти
Важный нюанс: Интернирование
Для оптимизации Python кэширует (интернирует) некоторые неизменяемые объекты, такие как малые целые числа (от -5 до 256) и короткие строки. В таких случаях is
может вернуть True
для разных переменных с одинаковым значением, хотя на это поведение не следует полагаться.
x = 256
y = 256
print(f"x is y: {x is y}") # True: число интернировано
m = 257
n = 257
print(f"m is n: {m is n}") # False: число не интернировано (в CPython)
Рекомендации
- Для сравнения значений (чисел, строк, списков) всегда используйте
==
. - Для проверки на
None
всегда используйтеis
, так какNone
является синглтоном. Это быстрее и является соглашением (PEP 8).if my_var is None: # ...
- Для проверки идентичности объектов используйте
is
, когда вам важно знать, что это один и тот же экземпляр в памяти.