В комментарии к этому вопросу я увидел утверждение, в котором рекомендуется использовать
result is not None
против
result != None
Мне было интересно, в чем разница, и почему один может быть рекомендован по сравнению с другим?
В комментарии к этому вопросу я увидел утверждение, в котором рекомендуется использовать
result is not None
против
result != None
Мне было интересно, в чем разница, и почему один может быть рекомендован по сравнению с другим?
Ответы:
==это тест на равенство . Он проверяет, являются ли правая сторона и левая сторона равными объектами (согласно их __eq__или __cmp__методам.)
isэто испытание личности . Он проверяет, являются ли правая сторона и левая сторона одним и тем же объектом. Методы не выполняются, объекты не могут влиять на isоперацию.
Вы используете is(и is not) для одиночных игр, например None, когда вас не волнуют объекты, которые вы хотите притвориться, Noneили где вы хотите защитить от разрушения объектов при сравнении с ними None.
Noneимеет мало методов и почти не имеет атрибутов. Если в вашем __eq__тесте ожидался метод или атрибут, он может сломаться. def __eq__( self, other ): return self.size == other.size, Например, сломается, если otherслучится None.
isпохож на Java ==. Питон ==похож на Java .equals(). Конечно, это помогает, только если вы знаете Java.
isэто похоже ===(очень равно), и наоборот is not, похоже !==(не совсем равно).
is notединственный оператор или это просто отрицание результата isкак внутри not foo is bar?
Во-первых, позвольте мне остановиться на нескольких терминах. Если вы просто хотите, чтобы на ваш вопрос ответили, прокрутите вниз до пункта «Ответ на ваш вопрос».
Идентификация объекта : когда вы создаете объект, вы можете назначить его переменной. Затем вы можете также назначить его другой переменной. И другой.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
В этом случае cancel, closeи dismissвсе они относятся к одному объекту в памяти. Вы создали только один Buttonобъект, и все три переменные ссылаются на этот один объект. Мы говорим, что cancel, closeи dismissвсе ссылаются на идентичные объекты; то есть они относятся к одному объекту.
Равенство объекта : Если сравнить два объекта, то , как правило , не волнует , что он относится к точному и тому же объекту в памяти. С помощью равенства объектов вы можете определить свои собственные правила сравнения двух объектов. Когда вы пишете if a == b:, вы, по сути, говорите if a.__eq__(b):. Это позволяет вам определить __eq__метод, aчтобы вы могли использовать свою собственную логику сравнения.
Обоснование: два объекта имеют одинаковые данные, но не идентичны. (Это не один и тот же объект в памяти.) Пример: строки
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Примечание: я использую строки Unicode здесь, потому что Python достаточно умен, чтобы повторно использовать обычные строки без создания новых в памяти.
Здесь у меня есть две строки Unicode, aи b. У них одинаковое содержание, но они не являются одним и тем же объектом в памяти. Однако, когда мы сравниваем их, мы хотим, чтобы они сравнивались на равных. Здесь происходит то, что объект Unicode реализовал __eq__метод.
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Примечание: __eq__он unicodeопределенно реализован более эффективно, чем этот.
Обоснование: два объекта имеют разные данные, но считаются одним и тем же объектом, если некоторые ключевые данные совпадают. Пример: большинство типов данных модели
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Здесь у меня есть два монитора Dell, aи b. Они имеют одинаковую марку и модель. Однако они не имеют одинаковых данных и не являются одним и тем же объектом в памяти. Однако, когда мы сравниваем их, мы хотим, чтобы они сравнивались на равных. Здесь происходит то, что объект Monitor реализует __eq__метод.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
При сравнении Noneвсегда используйте is not. Ни один из них не является синглтоном в Python - в памяти есть только один его экземпляр.
Сравнивая идентичность , это можно сделать очень быстро. Python проверяет, имеет ли объект, на который вы ссылаетесь, тот же адрес памяти, что и глобальный объект None, - очень и очень быстрое сравнение двух чисел.
Сравнивая равенство , Python должен выяснить, есть ли у вашего объекта __eq__метод. Если это не так, он проверяет каждый суперкласс в поисках __eq__метода. Если он находит, Python вызывает его. Это особенно плохо, если __eq__метод медленный и не сразу возвращается, когда замечает, что другой объект None.
Вы не реализовали __eq__? Тогда Python, вероятно, найдет __eq__метод objectи использует его вместо этого - который все равно проверяет идентичность объекта.
При сравнении большинства других вещей в Python вы будете использовать !=.
Учтите следующее:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
Noneявляется одноэлементным, поэтому сравнение идентичности всегда будет работать, тогда как объект может подделать сравнение на равенство через .__eq__().
None, но неправильное поведение в отношении Noneмогло бы возникнуть как побочный эффект от реализации равенства против других типов. Это не столько последствия для безопасности, сколько просто последствия для правильности.
>>> () есть () Правда >>> 1 есть 1 Правда >>> (1,) == (1,) Правда >>> (1,) есть (1,) Ложь >>> a = (1,) >>> б = а >>> а б Правда
Некоторые объекты являются синглетонами и, следовательно, isс ними эквивалентны ==. Большинство нет.
()и 1не являются по своей сути одиночками.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS) и пустые кортежи являются синглетонами. На самом деле это не задокументировано и не гарантировано, но вряд ли изменится.