Оригинальная статья: Olivera Popović — ‘is’ vs ‘==’ in Python — Object Comparison
В Python есть два очень похожих оператора для проверки равенства двух объектов. Эти два оператора is и ==.
Их обычно путаются друг с другом, потому что с простыми типами данных, такими как int и string (с которыми многие люди начинают изучать 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 есть два типа данных: изменяемые и неизменяемые.
Изменяемые типы данных: 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 чаще всего используется, когда мы хотим сравнить объект с None, и обычно рекомендуется ограничить его использование этим конкретным сценарием, если вы действительно (и я действительно имею в виду) не хотите проверить, идентичны ли два объекта.
Кроме того, обычно is быстрее, чем оператор ==, потому что он просто проверяет целочисленное равенство адреса памяти.
Важное примечание: единственная ситуация, когда is работает точно так, как можно было бы ожидать, это с singleton классами или объектами (как например с None). Даже с неизменяемыми объектами бывают ситуации, когда is не работает должным образом.
Например, для больших объектов string, генерируемых некоторой кодовой логикой или большими целыми числами int, is может (и будет) вести себя непредсказуемо. Если вы не пройдете interning (проверку) (т.е. убедитесь, что существует только одна копия string / int), Поведение равенства со всеми различными неизменяемые объектами, которые вы планируете использовать с is будут непредсказуемыми.
Суть в следующем: используйте == в 99% случаев.
Если два объекта идентичны, они также равны, и обратное не всегда верно.
Операторы != и is not не ведут себя так же, как их «положительные» коллеги (==/is). А именно, != возвращает True, если объекты не имеют одно и то же значение, в то время как is not не возвращает True, если объекты не хранятся в одном и том же адресе памяти.
Еще одно различие между этими двумя операторами заключается в том, что вы можете переопределить поведение == / != для пользовательского класса, в то время как вы не можете переопределить поведение is.
Если вы реализуете собственный метод __eq()__ в своем классе, вы можете изменить поведение операторов == / !=:
class TestingEQ: def __init__(self, n): self.n = n # используя '==', чтобы проверить, оба ли числа # четные, или если оба числа нечетные 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, поскольку он может вести себя непредсказуемо.
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
С целыми числами и строками всё не так просто. В питоне для первых 256 целых чисел используются предварительно созданные значения. Если мы используем такое число, питон не создаёт новое значение, а возвращает адрес готовой структуры.
In [1]: x = 256
In [2]: x == 256
Out[2]: True
In [3]: x is 256
Out[3]: True
In [4]: y = 257
In [5]: y == 257
Out[5]: True
In [6]: y is 257
Out[6]: False
С относительно длинными строками is тоже вернёт False
In [14]: s = 'gdfhjfdsnjkfndsjkfnjksd fdsflksgljnfsajgfsjngjkfdngjdfnjgkdfjkgnkjgnfjksngjkdsfnfdgjk'
In [15]: s == 'gdfhjfdsnjkfndsjkfnjksd fdsflksgljnfsajgfsjngjkfdngjdfnjgkdfjkgnkjgnfjksngjkdsfnfdgjk'
Out[15]: True
In [16]: s is 'gdfhjfdsnjkfndsjkfnjksd fdsflksgljnfsajgfsjngjkfdngjdfnjgkdfjkgnkjgnfjksngjkdsfnfdgjk'
Out[16]: False
Спасибо за толковый комментарий
In [8]: x=4
In [9]: x is not 3
Out[9]: True
Т.е. is not тоже возвращает True?
id([0]) == id([0])
out: True
a = id([0])
b = id([0])
a == b
out: False, если работаешь в терминале и True, если пускаешь скрипт.