Есть ли разница между "==" и "is"?
Мой Google-fu подвел меня.
Эквивалентны ли в Python следующие два теста на равенство?
n = 5
# Test one.
if n == 5:
print 'Yay!'
# Test two.
if n is 5:
print 'Yay!'
Справедливо ли это для объектов, в которых вы бы сравнивали экземпляры (list
скажем)?
Хорошо, это своего рода ответ на мой вопрос:
L = []
L.append(1)
if L == [1]:
print 'Yay!'
# Holds true, but...
if L is [1]:
print 'Yay!'
# Doesn't.
Итак, ==
проверяет значение, где is
проверяет, являются ли они одним и тем же объектом?
Переведено автоматически
Ответ 1
is
вернет, True
если две переменные указывают на один и тот же объект (в памяти), ==
если объекты, на которые ссылаются переменные, равны.
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True
# Make a new copy of list `a` via the slice operator,
# and assign it to variable `b`
>>> b = a[:]
>>> b is a
False
>>> b == a
True
В вашем случае второй тест работает только потому, что Python кэширует небольшие целочисленные объекты, что является деталью реализации. Для больших целых чисел это не работает:
>>> 1000 is 10**3
False
>>> 1000 == 10**3
True
То же самое справедливо и для строковых литералов:
>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True
Пожалуйста, ознакомьтесь также с этим вопросом.
Ответ 2
Существует простое эмпирическое правило, которое подскажет вам, когда использовать ==
или is
.
==
используется для равенства значений. Используйте его, когда хотите знать, имеют ли два объекта одинаковое значение.is
используется для равенства ссылок. Используйте его, когда хотите знать, ссылаются ли две ссылки на один и тот же объект.
В общем, когда вы сравниваете что-либо с простым типом, вы обычно проверяете равенство значений, поэтому вам следует использовать ==
. Например, цель вашего примера, вероятно, состоит в том, чтобы проверить, имеет ли x значение, равное 2 (==
), а не в том, x
ссылается ли оно буквально на тот же объект, что и 2.
Еще кое-что, на что следует обратить внимание: из-за того, как работает эталонная реализация CPython, вы получите неожиданные и противоречивые результаты, если по ошибке используете is
для сравнения эталонного равенства целых чисел:
>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False
Это почти то, чего мы ожидали: a
и b
имеют одинаковое значение, но являются разными сущностями. Но что насчет этого?
>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True
Это несовместимо с предыдущим результатом. Что здесь происходит? Оказывается, эталонная реализация Python кэширует целочисленные объекты в диапазоне -5 ..256 как одноэлементные экземпляры по соображениям производительности. Вот пример, демонстрирующий это:
>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
...
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False
Это еще одна очевидная причина не использовать is
: поведение остается на усмотрение реализаций, когда вы ошибочно используете его для равенства значений.
Ответ 3
Есть ли разница между
==
иis
в Python?
Да, у них есть очень важное различие.
==
: проверка на равенство - семантика такова, что эквивалентные объекты (которые не обязательно являются одним и тем же объектом) будут тестироваться как равные. Как говорится в документации:
Операторы <, >, ==, >=, <=, и != сравнивают значения двух объектов.
is
: проверка идентичности - семантика заключается в том, что объект (хранящийся в памяти) является объектом. Опять же, в документации говорится:
Операторы
is
иis not
проверяют идентичность объекта:x is y
истинно тогда и только тогда, когдаx
иy
являются одним и тем же объектом. Идентификация объекта определяется с помощьюid()
функции.x is not y
выдает обратное значение истинности.
Таким образом, проверка на идентичность аналогична проверке на равенство идентификаторов объектов. То есть,
a is b
это то же самое, что:
id(a) == id(b)
где id
- встроенная функция, возвращающая целое число, которое "гарантированно уникально среди одновременно существующих объектов" (см. help(id)
), а где a
и b
- любые произвольные объекты.
Другие направления использования
Вы должны использовать эти сравнения для их семантики. Используйте is
для проверки идентичности и ==
для проверки равенства.
Итак, в общем, мы используем is
для проверки идентичности. Обычно это полезно, когда мы проверяем объект, который должен существовать в памяти только один раз, в документации он называется "синглтоном".
Примеры использования для is
включают:
None
- значения перечисления (при использовании перечислений из модуля enum)
- обычно модули
- обычно объекты класса являются результатом определений классов
- обычно функциональные объекты являются результатом определений функций
- что-нибудь еще, что должно существовать в памяти только один раз (как правило, все синглтоны)
- конкретный объект, который вам нужен по идентификатору
Обычные варианты использования для ==
включают:
- числа, включая целые числа
- строки
- Списки
- Наборы
- словари
- пользовательские изменяемые объекты
- другие встроенные неизменяемые объекты, в большинстве случаев
Общий вариант использования, опять же, для ==
, is объект, который вы хотите, может быть не тем же объектом, вместо этого он может быть эквивалентным
PEP 8 directions
В PEP 8, официальном руководстве по стилю Python для стандартной библиотеки, также упоминаются два варианта использования для is
:
Сравнения с синглетами типа
None
всегда должны выполняться с помощьюis
oris not
, никогда операторов равенства.Кроме того, остерегайтесь писать,
if x
когда вы действительно имеете в видуif x is not None
- например, при проверке, была ли переменной или аргументу, значение которого по умолчанию равноNone
, присвоено какое-то другое значение. Другое значение может иметь тип (например, контейнер), который может быть false в логическом контексте!
Вывод равенства из идентичности
Если 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
Это работало при разработке. Возможно, он прошел некоторые unittests.
И это работало в рабочей среде - до тех пор, пока код не проверил целое число больше 256, после чего в рабочей среде произошел сбой.
Это производственный сбой, который мог быть обнаружен при проверке кода или, возможно, с помощью проверки стиля.
Позвольте мне подчеркнуть: не используйте is
для сравнения целых чисел.
Ответ 4
==
определяет, равны ли значения, в то время как is
определяет, являются ли они одним и тем же объектом.