Есть ли разница между "==" и "есть"? - PullRequest
612 голосов
/ 25 сентября 2008

Мой Google-фу подвел меня.

В 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 проверяет, являются ли они одним и тем же объектом?

Ответы [ 21 ]

819 голосов
/ 25 сентября 2008

is вернет True, если две переменные указывают на один и тот же объект, ==, если объекты, на которые ссылаются переменные, равны.

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True
>>> b = a[:] # Make a new copy of list `a` via the slice operator, and assign it to variable `b`
>>> 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

Пожалуйста, смотрите этот вопрос .

276 голосов
/ 06 июля 2009

Существует простое эмпирическое правило, указывающее, когда использовать == или 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: поведение оставлено на усмотрение реализаций, когда вы ошибочно используете его для равенства значений.

33 голосов
/ 25 сентября 2008

== определяет, равны ли значения, а is определяет, являются ли они точно таким же объектом и равными.

23 голосов
/ 05 января 2018

Есть ли разница между == и 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 для сравнения целых чисел.

17 голосов
/ 25 сентября 2008

Они совершенно разные . 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
16 голосов
/ 20 января 2018

В чем разница между is и ==?

== и is - это разные сравнения! Как уже говорили другие:

  • == сравнивает значения объектов.
  • is сравнивает ссылки объектов.

В именах Python ссылаются на объекты, например, в этом случае value1 и value2 ссылаются на экземпляр int, хранящий значение 1000:

value1 = 1000
value2 = value1

enter image description here

Поскольку value2 относится к одному и тому же объекту is и == даст True:

>>> value1 == value2
True
>>> value1 is value2
True

В следующем примере имена value1 и value2 относятся к разным int экземплярам, ​​даже если оба хранят одно и то же целое число:

>>> value1 = 1000
>>> value2 = 1000

enter image description here

Поскольку одно и то же значение (целое число) сохраняется, == будет True, поэтому его часто называют «сравнением значений». Однако is вернет False, потому что это разные объекты:

>>> value1 == value2
True
>>> value1 is value2
False

Когда использовать какой?

Обычно is - намного более быстрое сравнение. Вот почему CPython кеширует (или, возможно, повторно использует было бы более подходящим термином) определенные объекты, такие как маленькие целые числа, некоторые строки и т. Д. Но это следует рассматривать как подробности реализации , которые могут (даже если маловероятно) изменить в любой момент без предупреждения.

Вы должны использовать только is, если вы:

  • хочу проверить, действительно ли два объекта - это один и тот же объект (а не одно и то же «значение»). Один пример может быть, если вы используете одноэлементный объект в качестве константы.
  • хотите сравнить значение с Python константой . Константы в Python:

    • None
    • True 1
    • False 1
    • NotImplemented
    • Ellipsis
    • __debug__
    • классы (например int is int или int is float)
    • могут быть дополнительные константы во встроенных модулях или сторонних модулях. Например np.ma.masked из модуля NumPy)

В во всех остальных случаях вы должны использовать == для проверки на равенство.

Можно ли настроить поведение?

Есть некоторый аспект в ==, который не был упомянут в других ответах: Это часть Pythons "Модель данных" . Это означает, что его поведение можно настроить с помощью метода __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, поскольку обычно эти "проверки" используются в контексте, который неявно преобразует условие в логическое значение (например, в * 1175). * заявление). Таким образом, при is True сравнении и неявное логическое приведение выполняет больше работы, чем просто выполнение логического преобразования - и вы ограничиваетесь булевыми значениями (которые не считаются pythonic).

Как упоминается в PEP8:

Не сравнивайте логические значения с True или False, используя ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:
10 голосов
/ 25 сентября 2008

https://docs.python.org/library/stdtypes.html#comparisons

is тесты на личность == тесты на равенство

Каждое (маленькое) целочисленное значение отображается на одно значение, поэтому каждые 3 идентичны и равны. Это деталь реализации, а не часть спецификации языка, хотя

6 голосов
/ 25 сентября 2008

Ваш ответ правильный. Оператор is сравнивает идентичность двух объектов. Оператор == сравнивает значения двух объектов.

Идентичность объекта никогда не меняется после его создания; вы можете думать об этом как об адресе объекта в памяти.

Вы можете управлять поведением сравнения значений объекта, определив метод __cmp__ или расширенное сравнение , например __eq__.

4 голосов
/ 06 июля 2009

Посмотрите на вопрос переполнения стека Оператор Python «is» ведет себя неожиданно с целыми числами .

Что в основном сводится к тому, что "is" проверяет, являются ли они одним и тем же объектом, а не просто равны друг другу (числа ниже 256 являются особым случаем).

3 голосов
/ 06 августа 2018

Оператор == сравнивает значения обоих операндов и проверяет равенство значений. Принимая во внимание, что оператор is проверяет, относятся ли оба операнда к одному и тому же объекту.

a = [1,2,3,4]
b = a
print(a == b) # true
print(a is b) # true

Но если мы сделаем

b = a[:] # b now references a copy of a
print(a == b) # true
print(a is b) # false
print(a is not b) # true

По сути, is можно рассматривать как сокращение для id(a) == id(b). Тем не менее, помимо этого, существуют особенности среды выполнения, которые еще больше усложняют ситуацию. Короткие строки и маленькие целые числа возвращают True по сравнению с is из-за того, что машина Python пытается использовать меньше памяти для идентичных объектов.

a = 'python'
b = 'python'

print(a == b) # true
print(a is b) # true
...