Мой Гугл-фу подвел меня.
Эквивалентны ли следующие два теста на равенство в 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 проверяет, являются ли они одним и тем же объектом?






== определяет, равны ли значения, а is определяет, являются ли они одним и тем же объектом.
https://docs.python.org/library/stdtypes.html#comparisons
is тесты на идентичность
== тесты на равенство
Каждому (маленькому) целочисленному значению сопоставляется одно значение, поэтому каждые 3 идентичны и равны. Это деталь реализации, а не часть спецификации языка.
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
См. Также этот вопрос.
Вы потеряли меня из-за части копирования списка операторов срезов b = a[:], поэтому я отредактировал ваш ответ, чтобы добавить комментарий. Похоже, я только что достиг порога, чтобы мои правки не проверялись до их применения, так что, надеюсь, это нормально для вас. Тем не менее, вот полезный справочник о том, как копировать списки, с которыми я столкнулся и на которые мне пришлось ссылаться, чтобы понять, что вы делаете: stackoverflow.com/a/2612815/4561887
Другой способ продемонстрировать разницу - сравнить объекты разных типов, которые, конечно, никогда не могут быть одним и тем же объектом, но все равно сравнивать равные при использовании ==. Так, например, 5.0 - это значение с плавающей запятой, а 5 - целое число. Но 5.0 == 5 все равно будет возвращать True, потому что они представляют одно и то же значение. С точки зрения производительности и типизации, is всегда проверяется интерпретатором путем сравнения адресов памяти операнда, в то время как в случае == объект должен решить, определяет ли он себя как равный чему-то еще.
1000 is 10**3 оценивается как True в Python 3.7, поскольку 10 ** 3 - это тип int. Но 1000 is 1e3 оценивается как False, поскольку 1e3 - это тип float.
@AhmedFasih Независимо от того, является ли 1000 is 10**3 истинным, зависит от реализации и от компилятора, предварительно оценившего выражение 10**3. x=10; 1000 is x**3 соответствует False.
Ваш ответ правильный. Оператор is сравнивает идентичность двух объектов. Оператор == сравнивает значения двух объектов.
Идентичность объекта никогда не меняется после того, как он был создан; вы можете думать об этом как об адресе объекта в памяти.
Вы можете контролировать поведение сравнения значений объекта, определяя метод __cmp__ или метод богатое сравнение, например __eq__.
Это полностью отличается. is проверяет идентичность объекта, а == проверяет равенство (понятие, которое зависит от типов двух операндов).
То, что is, похоже, правильно работает с маленькими целыми числами (например, 5 == 4 + 1), является счастливым совпадением. Это потому, что CPython оптимизирует хранение целых чисел в диапазоне (от -5 до 256), делая их одиночными. Это поведение полностью зависит от реализации и не гарантируется, что оно будет сохранено при любых второстепенных операциях преобразования.
Например, Python 3.5 также создает синглтоны для коротких строк, но их разрезание нарушает это поведение:
>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False
Взгляните на вопрос о переполнении стека Оператор Python «is» неожиданно ведет себя с целыми числами..
В основном это сводится к тому, что «is» проверяет, являются ли они одним и тем же объектом, а не просто равны друг другу (числа ниже 256 являются особым случаем).
Существует простое практическое правило, которое подскажет, когда использовать == или 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: поведение остается на усмотрение реализаций, когда вы ошибочно используете его для равенства значений.
Что касается первого примера a=500 и b=500, просто хотел указать, что если вы установите a и b на промежуточное число между [-5, 256], a is b фактически вернет True. Подробнее здесь: stackoverflow.com/q/306313/7571052
@AsheKetchum, да, обратите внимание, что я написал: «Оказывается, эталонная реализация Python кэширует целочисленные объекты в диапазоне -5..256 как одноэлементные экземпляры из соображений производительности».
Так же, как добавить сюда два моих фрагмента. Используйте is, если вы хотите проверить, является ли это одним и тем же объектом (скажем, у вас есть список городов и объектов маршрута; вы можете сравнить местоположения или просто проверить, является ли он одним и тем же городом или нет - поэтому is является более сильным сравнением здесь) . В противном случае, если вас интересуют только примитивы, обычно == будет достаточно. Это скорее простое правило, которое будет нарушено, когда дела станут тяжелыми.
Как сказал Джон Феминелла, большую часть времени вы будете использовать == и! =, Потому что ваша цель - сравнить значения. Я просто хочу разделить на категории то, чем вы будете заниматься в остальное время:
Существует один и только один экземпляр NoneType, т.е. None не является одноэлементным. Следовательно, foo == None и foo is None означают одно и то же. Однако тест is быстрее, и по соглашению Pythonic следует использовать foo is None.
Если вы занимаетесь самоанализом или возитесь со сборкой мусора или проверяете, работает ли ваш специально созданный гаджет интернирования строк или что-то в этом роде, то у вас, вероятно, есть вариант использования foo - bar.
Истины и Ложь также (сейчас) синглтоны, но нет варианта использования для foo == True и нет варианта использования для foo is True.
Is there a difference between
==andisin Python?
Да, у них есть очень важное отличие.
==: проверка на равенство - семантика такова, что эквивалентные объекты (которые не обязательно являются одним и тем же объектом) будут проверяться как равные. Как документация говорит:
The operators <, >, ==, >=, <=, and != compare the values of two objects.
is: проверка идентичности - семантика такова, что объект (хранящийся в памяти) является объект. Опять же, документация говорит:
The operators
isandis nottest for object identity:x is yis true if and only ifxandyare the same object. Object identity is determined using theid()function.x is not yyields the inverse truth value.
Таким образом, проверка идентичности аналогична проверке совпадения идентификаторов объектов. То есть,
a is b
такой же как:
id(a) == id(b)
где id - встроенная функция, которая возвращает целое число, которое «гарантированно уникально среди одновременно существующих объектов» (см. help(id)), а a и b - любые произвольные объекты.
Вы должны использовать эти сравнения для их семантики. Используйте is для проверки идентичности и == для проверки равенства.
В общем, мы используем is для проверки личности. Обычно это полезно, когда мы проверяем объект, который должен существовать в памяти только один раз, в документации это называется «синглтоном».
Сценарии использования is включают:
NoneОбычные варианты использования == включают:
Общий вариант использования, опять же, для ==: объект, который вам нужен, может не быть объектом такой же, вместо этого он может быть объектом эквивалент.
PEP 8, официальное руководство по стилю Python для стандартной библиотеки, также упоминает два варианта использования is:
Comparisons to singletons like
Noneshould always be done withisoris not, never the equality operators.Also, beware of writing
if xwhen you really meanif x is not None-- e.g. when testing whether a variable or argument that defaults toNonewas set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
Если is истинно, можно сделать вывод о равенстве как правило - логически, если объект является самим собой, то он должен тестироваться как эквивалентный самому себе.
В большинстве случаев эта логика верна, но она зависит от реализации специального метода __eq__. Как говорят документы,
The default behavior for equality comparison (
==and!=) is based on the identity of the objects. Hence, equality comparison of instances with the same identity results in equality, and equality comparison of instances with different identities results in inequality. A motivation for this default behavior is the desire that all objects should be reflexive (i.e. x is y implies x == y).
и в интересах последовательности рекомендует:
Equality comparison should be reflexive. In other words, identical objects should compare equal:
x is yimpliesx == 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 вместо проверки на равенство.
Wow, this can lead to some insidious bugs. I had some code that checked if a is b, which worked as I wanted because a and b are typically small numbers. The bug only happened today, after six months in production, because a and b were finally large enough to not be cached. – gwg
Это сработало в разработке. Возможно, он прошел некоторые юнит-тесты.
И это работало в производстве - до тех пор, пока код не проверил целое число больше 256, после чего он отказал в производстве.
Это производственный сбой, который мог быть обнаружен при проверке кода или, возможно, с помощью средства проверки стиля.
Подчеркну: не используйте is для сравнения целых чисел.
«не использовать вообще» тоже было бы хорошим правилом. Идиоматический is None является исключением, но при этом == None тоже работает ...
@ Jean-FrançoisFabre Другое исключение: официальная документация, кажется, рекомендует использовать is для сравнения Enum.
Означает ли это, что два пользовательских класса сравниваются, например, a = Car ("новый"), B = Car ("новый"), если мы используем a == b, это равно a is b, я прав?
@UniSize Не думаю, что вы правы. Проблемы: 1. вы говорите a и B, но затем вы говорите a == b (нижний регистр) и Python чувствителен к регистру. 2. вы не говорите, должны ли a и b быть эквивалентными, но два экземпляра с одинаковыми аргументами подразумевают, что они эквивалентны, но не являются одними и теми же объектами, поэтому вы ошиблись бы в своей интерпретации. Пожалуйста, перечитайте мой ответ здесь и дайте мне знать, чего не хватает, и будьте осторожны и ясны в своем ответе.
@AaronHall Мои извинения, во-первых, это опечатка. Я пересмотрел это, a = Car ("новый"), b = Car ("новый"), если мы используем a == b, это равно a is b? Я понимаю, что «is» проверяет, находятся ли два объекта в одной и той же области памяти, а a == b - это сравнение двух объектов. На основании тестирования a == b возвращает false, а a is b также возвращает false. Почему при такой же инициализации a == b вернет false?
@UniSize Вот почему я сказал "подумайте" - реализация __eq__ по умолчанию использует is, и в этом случае вы были бы правы. Большинство пользовательских реализаций (и это должно быть сделано на ранних этапах жизненного цикла определения объекта, см. Мой доклад в PyGotham на эту тему: youtu.be/iGfggZqXmB0) обычно будут иметь два отдельных экземпляра с одинаковыми аргументами для теста создания экземпляра в качестве эквивалента - в этом случае вы будете неправильный. Вы все еще не сказали, эквивалентны ли a и b предполагаемый. Если вы не можете найти вопросы и ответы по этой теме, я предлагаю вам написать новый вопрос.
Стоит упомянуть, что a is b - это не обязательно, то же самое, что и id(a) == id(b), или что a и b не могут быть просто «ничем». Мое понимание is было основано на этом, и авторитетный учебник допустил ту же ошибку.
is и ==?== и is - разные сравнения! Как уже говорили другие:
== сравнивает значения объектов.is сравнивает ссылки на объекты.В Python имена относятся к объектам, например, в этом случае value1 и value2 относятся к экземпляру int, хранящему значение 1000:
value1 = 1000
value2 = value1
Поскольку value2 относится к одному и тому же объекту, is и == выдаст True:
>>> value1 == value2
True
>>> value1 is value2
True
В следующем примере имена value1 и value2 относятся к разным экземплярам int, даже если оба хранят одно и то же целое число:
>>> value1 = 1000
>>> value2 = 1000
Поскольку сохраняется одно и то же значение (целое число), == будет True, поэтому его часто называют «сравнением значений». Однако is вернет False, потому что это разные объекты:
>>> value1 == value2
True
>>> value1 is value2
False
В целом is - намного более быстрое сравнение. Вот почему CPython кэширует (или, может быть, повторно использует был бы лучшим термином) определенные объекты, такие как маленькие целые числа, некоторые строки и т. д. Но это следует рассматривать как детали реализации, который может (даже если маловероятно) измениться в любой момент без предупреждения.
Вам следует используйте только is, если вы:
хотите проверить, действительно ли два объекта являются одним и тем же объектом (а не одним и тем же «значением»). Одним из примеров может быть использование ты одноэлементного объекта в качестве константы.
хотите сравнить значение с Python постоянный. Константы в Python:
В в остальных случаях следует использовать == для проверки равенства.
Есть один аспект ==, который еще не упоминался в других ответах: это часть Питоны "Модель данных". Это означает, что его поведение можно настроить с помощью метода __eq__. Например:
class MyClass(object):
def __init__(self, val):
self._value = val
def __eq__(self, other):
print('__eq__ method called')
try:
return self._value == other._value
except AttributeError:
raise TypeError('Cannot compare {0} to objects of type {1}'
.format(type(self), type(other)))
Это просто искусственный пример, чтобы проиллюстрировать, что метод действительно вызывается:
>>> MyClass(10) == MyClass(10)
__eq__ method called
True
Обратите внимание, что по умолчанию (если в классе или суперклассах нет другой реализации __eq__) __eq__ использует is:
class AClass(object):
def __init__(self, value):
self._value = value
>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a
Поэтому на самом деле важно реализовать __eq__, если вы хотите «большего», чем просто сравнение ссылок для пользовательских классов!
С другой стороны, вы не можете настраивать проверки is. Он всегда будет сравнивать только, если у вас есть такая же ссылка.
Поскольку __eq__ может быть повторно реализован или отменен, он не ограничивается возвратом True или False. мог возвращает что угодно (но в большинстве случаев должно возвращать логическое значение!).
Например, с массивами NumPy == вернет массив:
>>> import numpy as np
>>> np.arange(10) == 2
array([False, False, True, False, False, False, False, False, False, False], dtype=bool)
Но проверки is всегда возвращают True или False!
1 Как упомянул Аарон Холл в комментариях:
Как правило, вам не следует выполнять какие-либо проверки is True или is False, потому что обычно эти «проверки» используются в контексте, который неявно преобразует условие в логическое значение (например, в операторе if). Таким образом, при сравнении is Trueи неявное логическое приведение выполняет больше работы, чем просто выполнение логического преобразования, и вы ограничиваете себя логическими значениями (что не считается питоническим).
Как упоминает PEP8:
Don't compare boolean values to
TrueorFalseusing==.Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
Мне придется не согласиться с вашим утверждением о сравнении «констант» с is - имена, указывающие на логические значения, следует проверять с помощью логического контекста - например, if __debug__: или if not __debug__:. Вы никогда не должны использовать if __debug__ is True: или if __debug__ == True: - кроме того, константа - это просто постоянное семантическое значение, а не одноэлемент, поэтому проверка с помощью is в этом случае семантически некорректна. Я призываю вас найти источник, подтверждающий ваши утверждения - я не думаю, что вы его найдете.
@AaronHall Почему вы думаете, что константы не синглтоны? Обратите внимание, что только None, True, False и __debug__ - это то, что вы бы назвали «постоянным семантическим значением», потому что их нельзя переназначить. Но все они одиночки.
Прочтите PEP 8 - Ctrl-F и найдите слово «хуже». - Если вы проводите модульное тестирование, вы должны использовать self.assertTrue
@AaronHall В некоторых случаях вам действительно нужна проверка is True или if False (но да, они довольно редки, но если вы их выполняете, вы может выполняете их с помощью is). Поэтому их иногда использует даже CPython (например, здесь или здесь)
Почему is True хуже == True? Может ли True is TrueКогда-либо выйти из строя? Если что-то == True более вероятно потерпит неудачу, так как __eq__ может быть заменен бессмыслицей, но не is.
@OverLordGoldDragon Речь идет не о неудаче, а просто о стиле (эта война скопирована из PEP8 - руководства по стилю Python). В конце концов, вам, вероятно, никогда не понадобится == True или is True (за исключением особых случаев или, возможно, в тестовом коде).
Не согласен с «никогда не is True»; У меня было несколько случаев, когда is True явно превосходит свои альтернативы по простоте и удобочитаемости, и я видел, как он и is False использовались в основном производственном коде API. Это звучит как совет «не используйте exec», который действителен, но чрезмерно раздут («никогда»).
@OverLordGoldDragon В программировании нет ничего без исключения. Он также не преувеличен ... «Никогда не используйте exec или is True» - это совет, чтобы защитить читателей (включая более неопытных программистов или случайных прохожих) от самих себя. Обычно предполагается, что люди, достаточно опытные в программировании, будут знать, когда нарушать правила.
Поскольку другие люди в этом сообщении подробно отвечают на вопрос о разнице между == и is для сравнения объектов или переменных, я бы подчеркивать в основном сравнивал is и ==для струнных, которые могут давать разные результаты, и я бы призвал программистов осторожно их использовать.
Для сравнения строк обязательно используйте == вместо is:
str = 'hello'
if (str is 'hello'):
print ('str is hello')
if (str == 'hello'):
print ('str == hello')
Из:
str is hello
str == hello
Но в приведенном ниже примере == и is получат разные результаты:
str2 = 'hello sam'
if (str2 is 'hello sam'):
print ('str2 is hello sam')
if (str2 == 'hello sam'):
print ('str2 == hello sam')
Из:
str2 == hello sam
Заключение и анализ:
Осторожно используйте is для сравнения строк.
Начиная с is для сравнения объектов и поскольку в Python 3+ каждая переменная, такая как строка, интерпретируется как объект, давайте посмотрим, что произошло в приведенных выше абзацах.
В python есть функция id, которая показывает уникальную константу объекта во время его жизни. Этот идентификатор используется во внутренней части интерпретатора Python для сравнения двух объектов с использованием ключевого слова is.
str = 'hello'
id('hello')
> 140039832615152
id(str)
> 140039832615152
Но
str2 = 'hello sam'
id('hello sam')
> 140039832615536
id(str2)
> 140039832615792
почему "is" работает так для строк с пробелами?
Согласно предыдущим ответам: кажется, что python выполняет кэширование небольших целых чисел и строк, что означает, что он использует одну и ту же ссылку на объект для вхождений строки hello в этом снимке кода, в то время как он не выполнял кеширование для 'hello sam', как есть относительно больше, чем 'hello' (т.е. он управляет различными ссылками на строку 'hello sam', и поэтому оператор 'is' возвращает false в следующем примере) Исправьте меня, если я ошибаюсь
@AkashGupta извините за задержку с ответом. Я просто добавил еще несколько объяснений, почему это произошло в интерпретаторе Python. Надеюсь, это будет полезно.
Большинство из них уже ответили по существу. В качестве дополнительного примечания (на основе моего понимания и экспериментов, но не из документированного источника) утверждение
== if the objects referred to by the variables are equal
из приведенных выше ответов следует читать как
== if the objects referred to by the variables are equal and objects belonging to the same type/class
. Я пришел к такому выводу на основании следующего теста:
list1 = [1,2,3,4]
tuple1 = (1,2,3,4)
print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))
print(list1 == tuple1)
print(list1 is tuple1)
Здесь содержимое списка и кортежа одинаковы, но тип / класс различаются.
Вкратце, is проверяет, указывают ли две ссылки на один и тот же объект или нет. == проверяет, имеют ли два объекта одинаковое значение или нет.
a=[1,2,3]
b=a #a and b point to the same object
c=list(a) #c points to different object
if a==b:
print('#') #output:#
if a is b:
print('##') #output:##
if a==c:
print('###') #output:##
if a is c:
print('####') #no output as c and a point to different object
Разница в Python между is и equals (==)
The is operator may seem like the same as the equality operator but they are not same.
The is checks if both the variables point to the same object whereas the == sign checks if the values for the two variables are the same.
So if the is operator returns True then the equality is definitely True, but the opposite may or may not be True.
Вот пример, демонстрирующий сходство и различие.
>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.
Пожалуйста, используйте блочные кавычки только для текста, который вы цитируете из другого источника, в этот момент вы должны указать авторство (см. stackoverflow.com/help/referencing). Если это ваш собственный текст, удалите кавычки.
Я обнаружил, что: Выход
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo:False True False.