== и is в Python: разница, примеры и лучшие практики для начинающих
Запрос «== vs is в Python» — один из самых частых у начинающих. Несмотря на простоту, эта тема регулярно вызывает ошибки в продакшене. Разберёмся глубоко и практично: что такое равенство и идентичность объектов, где каждый оператор уместен, и как избежать тонких багов.
Коротко: в чём разница между == и is
- == сравнивает значения объектов (логическое равенство). Может вызывать метод
__eq__у объектов. - is сравнивает идентичность — являются ли это одним и тем же объектом в памяти (тот же
id()).
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True: значения списков равны
print(a is b) # False: это разные объекты
print(a is c) # True: c указывает на тот же объект, что и a
Числа и строки: почему иногда «везёт», а иногда — нет
В CPython интернируются некоторые маленькие объекты (например, целые числа в небольшом диапазоне и строковые литералы). Это оптимизация, а не правило языка. Нельзя на неё рассчитывать в логике программы.
# Пример с целыми числами
a = 256
b = 256
print(a is b) # Часто True в CPython (кэш малых int), но это не гарантия стандарта
x = 10_000
y = 10_000
print(x is y) # Часто False: большие int не кешируются одинаково
# Пример со строками
s1 = "hello"
s2 = "hello"
print(s1 is s2) # Часто True (литералы могут интернироваться)
s3 = "he" + "llo" # Компилятор может склеить во время компиляции
print(s1 is s3) # Может быть True
s4 = "he" + input() # Формируется во время выполнения
print(s1 == s4) # Сравнивайте по значению
print(s1 is s4) # Не полагайтесь на это — почти наверняка False
Если вам действительно нужен контроль за интернированием строк (редко нужно), используйте sys.intern.
import sys
s1 = sys.intern("very_long_key_value")
s2 = sys.intern("very_" + "long_key_value")
print(s1 is s2) # True: теперь это один и тот же объект в кеше интернировщика
Когда использовать is: None и синглтоны
Оператор is уместен для сравнения с None и другими синглтонами (уникальными объектами), потому что у них есть ровно один экземпляр.
result = None
# Правильно
if result is None:
print("Пока результата нет")
# Неправильно
if result == None: # pep8: E711 — используйте is None
pass
Аналогично, True и False — синглтоны. Но писать if flag is True: считается дурным тоном — используйте просто if flag:.
flag = True
# Плохо
if flag is True:
...
# Хорошо
if flag:
...
# Проверка на ложность без is False
if not flag:
...
Пользовательские классы и __eq__: равные, но не идентичные
Оператор == вызывает метод __eq__ (если он определён). Так объекты могут быть «равны по значению», не будучи одним и тем же объектом.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if isinstance(other, Point):
return (self.x, self.y) == (other.x, other.y)
return NotImplemented
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # True: равны по значению
print(p1 is p2) # False: разные объекты
Если __eq__ не реализован, унаследованное сравнение от object фактически ведёт себя как сравнение идентичности: разные экземпляры будут «не равны» по == даже с одинаковыми полями.
Контейнеры: == сравнивает поэлементно, is — ссылку на объект
Списки, кортежи, множества и словари сравниваются по содержимому при помощи ==. Оператор is уместен только для проверки, что это именно тот же самый контейнер (та же ссылка).
a = [1, 2]
b = [1, 2]
c = a
print(a == b) # True: поэлементное равенство
print(a is b) # False
print(a is c) # True
# Осторожно с общей ссылкой
c.append(3)
print(a) # [1, 2, 3] — изменился и a, и c, потому что это один объект
Особый случай: NaN — ничему не равен, даже себе
По стандарту IEEE 754, NaN «не равно ничему, даже самому себе». Поэтому проверки вида x == float('nan') всегда дадут False. Оператор is тут тоже не поможет: создаются разные объекты NaN.
import math
nan1 = float('nan')
nan2 = float('nan')
print(nan1 == nan2) # False
print(nan1 is nan2) # False
print(math.isnan(nan1)) # True — правильная проверка
В NumPy используйте numpy.isnan или pandas.isna для векторизованных проверок — сравнение через == и тем более is там тоже не подходит.
Производительность: is быстрее, но выбирайте корректность
is — очень быстрая операция (сравнивает адреса объектов), но использовать её «для скорости» там, где требуется равенство значений, — ошибка. Сначала корректность, затем — микропроизводительность.
Частые ошибки и как их исправить
- Сравнение строк через
is: используйте==. - Сравнение чисел через
is: используйте==(а для float при необходимости — сравнение с допуском черезmath.isclose). - Проверка на
Noneчерез==: используйтеis Noneиis not None. - Проверка булей через
is True/is False: используйтеif flagилиif not flag. - Опора на интернирование объектов (числа/строки) для логики: это деталь реализации, избегайте.
Практическая памятка
- Нужно сравнить значения? Используйте ==.
- Нужно проверить, что объект — именно
None(или другой синглтон)? Используйте is. - С контейнерами:
==— по содержимому,is— та же ссылка. - С плавающей точкой: для близости значений используйте
math.isclose. - Для NaN:
math.isnan/numpy.isnan/pandas.isna.
Небольшие упражнения для закрепления
# 1) Что выведет код и почему?
a = 1000
b = 10**3
print(a == b)
print(a is b)
# 2) Исправьте условие так, чтобы корректно проверять отсутствие значения:
value = None
if value == None: # <-- исправить
print("пусто")
# 3) Почему так и как правильно?
nan = float('nan')
print(nan == nan)
# Сделайте корректную проверку на NaN
Куда двигаться дальше
Вы разобрались с ключевой парой операторов «== vs is в Python». Следующий шаг — практиковаться на реальных задачах и укреплять базу языка: типы данных, функции, тестирование, работа с файлами и сетевыми запросами. Отличный путь — пройти структурированный практический курс с заданиями и обратной связью.
Хочу быстро прокачаться на курсе «Программирование на Python с Нуля до Гуру» →
Выводы
==— для сравнения значений;is— для сравнения идентичности объектов.- С
Noneвсегда используйтеis. - Не полагайтесь на интернирование чисел и строк для логики.
- Учитывайте особенности float и NaN; выбирайте правильные функции сравнения.
С этими правилами ваши проверки станут предсказуемыми и безопасными в любом окружении Python.
-
Создано 08.06.2026 17:01:15
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.