Рубрики
Без рубрики

‘is’ vs ‘==’ in Python – Object Comparation

В этом уроке мы погрузимся в разницу между ” is “и рассмотрим случаи использования обоих вариантов и перегрузим оператор “= = ” для сравнения пользовательских значений.

Автор оригинала: Olivera Popović.

‘is’ vs ‘==’ in Python – Object Comparation

‘is’ vs ‘==’ в Python

В Python есть два очень похожих оператора для проверки того, равны ли два объекта. Эти два оператора являются is и == .

Они обычно путаются друг с другом, потому что с простыми типами данных, такими как int и string s (с которыми многие люди начинают изучать Python), они, кажется, делают то же самое:

x = 5
s = "example"

print("x == 5: " + str(x == 5))
print("x is 5: " + str(x is 5))
print("s == 'example': " + str(s == "example"))
print("s is 'example': " + str(s is "example"))

Запуск этого кода приведет к:

x == 5: True
x is 5: True
s == 'example': True
s is 'example': True

Это показывает, что == и is возвращают одно и то же значение ( True ) в этих случаях. Однако если вы попытаетесь сделать это с более сложной структурой:

some_list = [1]

print("some_list == [1]: " + str(some_list == [1]))
print("some_list is [1]: " + str(some_list is [1]))

Это привело бы к:

some_list == [1]: True
some_list is [1]: False

Здесь становится очевидным, что эти операторы не одно и то же.

Разница заключается в том , что is проверяет идентичность (объектов) , в то время как == проверяет равенство (значения) .

Вот еще один пример, который может прояснить разницу между этими двумя операторами:

some_list1 = [1]
some_list2 = [1]
some_list3 = some_list1

print("some_list1 == some_list2: " + str(some_list1 == some_list2))
print("some_list1 is some_list2: " + str(some_list1 is some_list2))
print("some_list1 == some_list3: " + str(some_list1 == some_list3))
print("some_list1 is some_list3: " + str(some_list1 is some_list3))

Это приводит к:

some_list1 == some_list2: True
some_list1 is some_list2: False
some_list1 == some_list3: True
some_list1 is some_list3: True

Как мы видим, some_list 1 равен //some_list 2 по значению (они оба равны [1] ]), но они не являются идентичными , что означает, что они не являются одним и тем же объектом, даже если они имеют равные значения.

Однако some_list1 является одновременно равным и идентичным | some_list3 , поскольку они ссылаются на один и тот же объект в памяти.

Изменяемые и Неизменяемые типы данных

Хотя эта часть проблемы теперь может быть ясна (когда мы назвали переменные), может возникнуть другой вопрос:

Как получилось, что is и == ведут себя одинаково с неназванными int и string значениями (например 5 и "пример" ), но не ведут себя так же с безымянными списками (например, [1] )?

В Python существует два типа типов данных – mutable и immutable .

  • Изменяемые типы данных-это типы данных, которые вы можете “изменять” с течением времени
  • Неизменяемые типы данных остаются неизменными (имеют одну и ту же ячейку памяти, что и проверка is ) после их создания

Изменяемыми типами данных являются: list , dictionary , set и пользовательские классы.

Неизменяемыми типами данных являются: int , float , decimal , bool , string , tuple и range .

Как и многие другие языки, Python обрабатывает неизменяемые типы данных иначе, чем изменяемые, то есть сохраняет их в памяти только один раз.

Так что каждый 5 вы используете в своем коде точно такое же 5 вы используете его в других местах своего кода, и то же самое относится к строковым литералам, которые вы используете.

Если вы используете строку "example" один раз, то каждый раз, когда вы используете "example" это будет точно такой же объект. См. Это Примечание для получения дополнительных разъяснений.

Мы будем использовать функцию Python под названием id () , которая выводит уникальный идентификатор для каждого объекта, чтобы поближе взглянуть на эту концепцию изменчивости в действии:

s = "example"
print("Id of s: " + str(id(s)))
print("Id of the String 'example': " + str(id("example")) + " (note that it's the same as the variable s)")
print("s is 'example': " + str(s is "example"))

print("Change s to something else, then back to 'example'.")
s = "something else"
s = "example"
print("Id of s: " + str(id(s)))
print("s is 'example': " + str(s is "example"))
print()

list1 = [1]
list2 = list1
print("Id of list1: " + str(id(list1)))
print("Id of list2: " + str(id(list2)))
print("Id of [1]: " + str(id([1])) + " (note that it's not the same as list1!)")
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))

print("Change list1 to something else, then back to the original ([1]) value.")
list1 = [2]
list1 = [1]
print("Id of list1: " + str(id(list1)))
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))

Это выводит:

Id of s: 22531456
Id of the String 'example': 22531456 (note that it's the same as the variable s)
s is 'example': True
Change s to something else, then back to 'example'.
Id of s: 22531456
s is 'example': True

Id of list1: 22103504
Id of list2: 22103504
Id of [1]: 22104664 (note that it's not the same as list1!)
list1 == list2: True
list1 is list2: True
Change list1 to something else, then back to the original ([1]) value.
Id of list1: 22591368
list1 == list2: True
list1 is list2: False

Мы видим, что в первой части примера s возвращается к тому же самому "примеру" объекту, которому он был назначен в начале, даже если мы тем временем изменим значение s .

Однако list не возвращает тот же объект , значение которого равно [1] , но создается совершенно новый объект, даже если он имеет то же значение , что и первый [1] .

Если вы запустите приведенный выше код, вы, скорее всего, получите разные идентификаторы для объектов, но равенства будут одинаковыми.

Когда используются “is” и “==” Соответственно?

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

Кроме того, is обычно быстрее, чем оператор == , потому что он просто проверяет целочисленное равенство адреса памяти.

Важное примечание: Единственная ситуация, когда is работает точно так, как можно было бы ожидать, – это с singleton classes/objects (например, None ). Даже с неизменяемыми объектами существуют ситуации, когда is does not работает так, как ожидалось.

Например, для больших string объектов, генерируемых некоторой логикой кода, или больших int s, is может (и будет) вести себя непредсказуемо. Если вы не приложите усилий к интернированию (то есть не будете абсолютно уверены, что существует только одна копия string /| int | и т. Д.), Все различные неизменяемые объекты, которые вы планируете использовать,/| is будут непредсказуемы.

Суть такова: используйте == в 99% случаев.

Если два объекта идентичны они также равны , и что противоположное не обязательно верно.

Переопределение!=’ Операторов

Операторы != и is not ведут себя так же, как и их “положительные” аналоги. А именно, != возвращает True если объекты не имеют одного и того же значения, в то время как is not возвращает True если объекты не хранятся в одном и том же адресе памяти.

Еще одно различие между этими двумя операторами заключается в том, что вы можете переопределить поведение == / != для пользовательского класса, в то время как вы не можете переопределить поведение is .

Если вы реализуете пользовательский метод __eq()__ в своем классе, вы можете изменить способ == / != операторы ведут себя:

class TestingEQ:
    def __init__(self, n):
        self.n = n

    # using the '==' to check whether both numbers
    # are even, or if both numbers are odd
    def __eq__(self, other):
        if (self.n % 2 == 0 and other % 2 == 0):
            return True
        else:
            return False


print(5 == TestingEQ(1))
print(2 == TestingEQ(10))
print(1 != TestingEQ(2))

Это приводит к:

False
True
True

Вывод

Короче говоря, == / != проверьте равенство (по значению) и is /is not проверьте , являются ли два объекта идентичными , т. е. проверяет их адреса памяти.

Однако избегайте использования is , если вы точно не знаете, что делаете , или когда имеете дело с одноэлементными объектами, такими как None , так как они могут вести себя непредсказуемо.