← Назад к вопросам
Чем отличаются операторы == и is в Python?
2.0 Middle🔥 121 комментариев
#DevOps и инфраструктура#Django
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Чем отличаются операторы == и is в Python?
Это один из самых важных различий в Python, которое нужно понимать для корректной работы с объектами. Операторы выглядят похоже, но работают совершенно по-разному.
Основное различие
== (equals) — сравнивает ЗНАЧЕНИЯ
- Проверяет, равны ли содержимое объектов
- Использует метод
__eq__() - Возвращает True, если значения одинаковые
is — сравнивает ИДЕНТИЧНОСТЬ (адреса памяти)
- Проверяет, указывают ли переменные на один и тот же объект
- Не вызывает методы, сравнивает адреса в памяти
- Возвращает True, только если это один и тот же объект
Примеры
# Пример 1: Списки
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True (содержимое одинаковое)
print(a is b) # False (разные объекты в памяти)
print(a is c) # True (одна переменная указывает на другую)
print(id(a)) # Адрес объекта a
print(id(b)) # Другой адрес
print(id(c)) # Тот же адрес, что и у a
Визуально
=== С == ===
a = [1, 2, 3] -----> [1, 2, 3] (объект в памяти)
b = [1, 2, 3] -----> [1, 2, 3] (другой объект в памяти)
a == b # True (значения совпадают)
a is b # False (разные адреса)
=== С is ===
a = [1, 2, 3] ---->
b = a ----+ (одна ссылка)
a is b # True (одна и та же ячейка памяти)
Практические примеры
Числа и строки (интернирование)
# Для маленьких чисел Python кэширует объекты
a = 256
b = 256
print(a == b) # True
print(a is b) # True (оба указывают на закэшированный объект)
# Для больших чисел
x = 257
y = 257
print(x == y) # True
print(x is y) # False (в REPL обычно True, но в модуле False)
# Строки
s1 = "hello"
s2 = "hello"
print(s1 == s2) # True
print(s1 is s2) # True (интернирование строк)
# Но если строки созданы динамически
s3 = "".join(["h", "e", "l", "l", "o"])
print(s1 == s3) # True
print(s1 is s3) # False (динамическая строка не интернируется)
Более сложные объекты
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return isinstance(other, Person) and self.name == other.name
p1 = Person("Alice")
p2 = Person("Alice")
p3 = p1
print(p1 == p2) # True (переопределили __eq__, сравниваем имена)
print(p1 is p2) # False (разные объекты)
print(p1 is p3) # True (один объект)
Таблица истины
Operation | Проверяет | Использует | Применение
-------------|------------------|------------------|------------------
== | Значение | __eq__() метод | Равенство данных
is | Идентичность | id() функция | Проверка None, True, False
!= | Не равно | __ne__() метод | Неравенство
is not | Не идентично | id() функция | Проверка не-None
Правильное использование
# ПРАВИЛЬНО: сравнение с None, True, False
if x is None:
pass
if x is True: # специальный случай
pass
if x is False:
pass
# НЕПРАВИЛЬНО (хотя часто работает):
if x == None: # ПЛОХО, используй 'is None'
pass
# ПРАВИЛЬНО: сравнение значений
if a == b:
pass
if "hello" == user_input:
pass
if [1, 2, 3] == my_list:
pass
Производительность
import timeit
# is — очень быстро (просто сравнение адресов)
print(timeit.timeit('None is None', number=10000000)) # ~0.2 секунды
# == — медленнее (вызывает метод)
print(timeit.timeit('[1,2,3] == [1,2,3]', number=100000)) # ~0.5 секунд
Поэтому для None, True, False ВСЕГДА используй is.
Кэширование и интернирование
Python оптимизирует память для часто используемых значений:
# Целые числа от -5 до 256 всегда кэшируются
a = 10
b = 10
print(a is b) # True
# Строки
string_intern = sys.intern("my_string")
# Интернированные строки сравниваются по идентичности быстрее
# Списки и словари НИКОГДА не интернируются
list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(list1 is list2) # False (всегда)
Переопределение eq
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
"""Два точки равны, если их координаты совпадают."""
if not isinstance(other, Point):
return False
return self.x == other.x and self.y == other.y
def __hash__(self):
"""Если переопределили __eq__, нужно переопределить __hash__."""
return hash((self.x, self.y))
p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = p1
print(p1 == p2) # True
print(p1 is p2) # False
print(p1 is p3) # True
# Теперь Point можно использовать в set и dict
points = {p1, p2} # Будет один элемент, т.к. p1 == p2
print(len(points)) # 1
Проверка знаний на интервью
# Вопрос: Что выведет?
x = []
y = []
print(x == y) # True (пустые списки равны по значению)
print(x is y) # False (разные объекты)
# Вопрос: Что выведет?
a = None
b = None
print(a == b) # True
print(a is b) # True (None — единственный объект)
# Вопрос: Правильная ли проверка?
if my_var is None: # ПРАВИЛЬНО
pass
if my_var == None: # ПЛОХАЯ ПРИВЫЧКА
pass
Когда использовать что
| Ситуация | Оператор | Объяснение |
|---|---|---|
| Проверка None | is None | Стандарт Python |
| Проверка True/False | == (или просто if x:) | Обычно == или без проверки |
| Сравнение чисел | == | Значения могут быть равны |
| Сравнение строк | == | Сравнивают содержимое |
| Сравнение списков | == | Сравнивают элементы |
| Проверка одного объекта | is | Идентичность памяти |
| Кэширование | is | Оптимизация по памяти |
Лучшие практики
# Хорошо
if value is None:
pass
if value is not None:
pass
if a == b: # Для сравнения значений
pass
# Плохо
if value == None:
pass
if value != None:
pass
if not (a is b): # Используй 'is not'
pass
Итоговая таблица
Выражение Проверяет Используй когда
== Значения Сравниваешь данные
!= Не равны Противоположно ==
is Идентичность объекта Проверяешь None, True, False
is not Не идентичны Проверяешь не-None, не-True