Есть ли разница между ==
и is
в Python?
Да, у них есть очень важное различие.
==
: проверка на равенство - семантика состоит в том, что эквивалентные объекты (которые не обязательно являются одним и тем же объектом) будут проверяться как равные. Как сказано в документации :
Операторы <,>, ==,> =, <= и! = Сравнивают значения двух объектов. </p>
is
: проверка идентичности - семантика состоит в том, что объект (как хранится в памяти) является объектом. Опять же, в документации написано :
Операторы is
и is not
проверяют идентичность объекта: x is y
имеет значение true
тогда и только тогда, когда x
и y
являются одним и тем же объектом. Идентичность объекта
определяется с помощью функции id()
. x is not y
дает обратное
Значение истины.
Таким образом, проверка на идентичность аналогична проверке на равенство идентификаторов объектов. То есть
a is b
совпадает с:
id(a) == id(b)
, где id
- встроенная функция, которая возвращает целое число, которое «гарантированно будет уникальным среди одновременно существующих объектов» (см. help(id)
) и где a
и b
- любые произвольные объекты.
Другие инструкции по применению
Вы должны использовать эти сравнения для их семантики. Используйте is
для проверки личности и ==
для проверки равенства.
PEP 8, официальное руководство по стилю Python для стандартной библиотеки, также упоминает два варианта использования для is
:
Сравнение с синглетонами, такими как None
, всегда следует делать с is
или
is not
, никогда операторы равенства.
Кроме того, остерегайтесь писать if x
, когда вы действительно имеете в виду if x is not None
-
например при проверке, является ли переменная или аргумент по умолчанию None
было установлено какое-то другое значение. Другое значение может иметь тип (например,
как контейнер), который может быть ложным в логическом контексте!
Вывод равенства из идентичности
Если is
истинно, равенство может обычно выводиться - логически, если объект сам по себе, то он должен проверяться как эквивалентный самому себе.
В большинстве случаев эта логика верна, но она основана на реализации специального метода __eq__
. Как говорят документы ,
Поведение по умолчанию для сравнения равенства (==
и !=
) основано на
личность объектов. Следовательно, сравнение равенство экземпляров
с одинаковой идентичностью приводит к равенству, и сравнение равенства
случаи с разными идентичностями приводят к неравенству.
мотивом для этого поведения по умолчанию является желание, чтобы все объекты
должен быть рефлексивным (то есть x означает y означает x == y).
и в интересах последовательности рекомендует:
Сравнение равенства должно быть рефлексивным. Другими словами, идентичные
объекты должны сравниваться равными:
x is y
подразумевает x == y
Мы видим, что это поведение по умолчанию для пользовательских объектов:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
Противоположное также обычно верно - если что-то проверяется как не равное, вы можете сделать вывод, что это не один и тот же объект.
Поскольку тесты на равенство можно настраивать, этот вывод не всегда верен для всех типов.
Исключение
Заметным исключением является nan
- оно всегда проверяется как не равное себе:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Проверка на идентичность может быть намного быстрее, чем проверка на равенство (что может потребовать рекурсивной проверки членов).
Но его нельзя заменить равенством, когда вы можете найти более одного объекта в качестве эквивалентного.
Обратите внимание, что сравнение равенства списков и кортежей предполагает, что идентичность объектов одинакова (потому что это быстрая проверка). Это может создать противоречия, если логика противоречива - как это для nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Поучительная история:
Вопрос пытается использовать is
для сравнения целых чисел. Не следует предполагать, что экземпляр целого числа совпадает с экземпляром, полученным по другой ссылке. Эта история объясняет почему.
Комментатор имел код, основанный на том факте, что маленькие целые числа (от -5 до 256 включительно) в Python являются синглетонами вместо проверки на равенство.
Ух ты, это может привести к некоторым коварным ошибкам. У меня был какой-то код, который проверял, является ли a b, и работал, как я хотел, потому что a и b, как правило, небольшие числа. Ошибка произошла только сегодня, после шести месяцев работы, потому что a и b были достаточно большими, чтобы их нельзя было кэшировать. - GWG
Работало в разработке. Возможно, прошло несколько юнит-тестов.
И он работал в производстве - до тех пор, пока код не проверил целое число больше 256, и в этот момент он не заработал.
Это производственный сбой, который мог быть обнаружен при проверке кода или, возможно, с помощью средства проверки стиля.
Позвольте мне подчеркнуть: не используйте is
для сравнения целых чисел.