'is' vs '==' - Сравнение объектов Python

'is' vs '==' в Python В Python есть два очень похожих оператора для проверки равенства двух объектов. Эти два оператора - это и ==. Их обычно путают друг с другом, потому что с простыми типами данных, такими как целые числа и строки (с которых многие люди начинают изучать 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"))

'is' vs '==' в Python

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

Их обычно путают друг с другом, потому что с простыми типами данных, такими как int s и 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_list1 равен some_list2 по значению (они оба равны [1] ]), но они не идентичны , то есть это не один и тот же объект, даже если они имеют равные значения.

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

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

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

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

В Python есть два типа типов данных - изменяемые и неизменяемые .

  • Изменяемые типы данных - это типы данных, которые вы можете "изменять" с течением времени.
  • Неизменяемые типы данных остаются неизменными (имеют одно и то же место в памяти, что и 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 вернул тот же "example" которому он был назначен в начале, даже если мы тем временем s

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

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

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

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

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

[Важное примечание:]{#note} единственная ситуация, когда is работает именно так, как можно было бы ожидать, - это одноэлементные классы / объекты (например, None ). Даже неизменные объекты, бывают ситуации , когда is не работает , как ожидалось.

Например, для больших 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 , поскольку они могут вести себя непредсказуемо.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus