Python! = Операция против "нет" - PullRequest
205 голосов
/ 05 февраля 2010

В комментарии к на этот вопрос я увидел утверждение, в котором рекомендуется использовать

result is not None

против

result != None

Мне было интересно, в чем разница, и почему одно может быть рекомендовано над другим?

Ответы [ 5 ]

254 голосов
/ 05 февраля 2010

== является тестом на равенство .Он проверяет, являются ли правая и левая стороны равными объектами (в соответствии с их __eq__ или __cmp__ методами.)

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

Вы используете isis not) для синглетонов, например None, где вас не волнуют объектыВозможно, вы захотите притвориться None или где вы хотите защитить от разрушения объектов при сравнении с None.

127 голосов
/ 05 февраля 2010

Во-первых, позвольте мне остановиться на нескольких терминах. Если вы просто хотите, чтобы на ваш вопрос ответили, прокрутите вниз до пункта «Ответ на ваш вопрос».

Определения

Идентификатор объекта : Когда вы создаете объект, вы можете назначить его переменной. Затем вы можете также назначить его другой переменной. И еще один.

>>> 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 - в памяти только один его экземпляр.

Сравнивая identity , это можно сделать очень быстро. Python проверяет, имеет ли объект, на который вы ссылаетесь, тот же адрес памяти, что и глобальный объект None, - очень и очень быстрое сравнение двух чисел.

Сравнивая равенство , Python должен выяснить, есть ли у вашего объекта метод __eq__. Если это не так, он проверяет каждый суперкласс в поисках метода __eq__. Если он находит, Python вызывает его. Это особенно плохо, если метод __eq__ медленный и не сразу возвращается, когда замечает, что другой объект - None.

Вы не внедрили __eq__? Тогда Python, вероятно, найдет метод __eq__ в object и использует его вместо этого - который в любом случае просто проверяет подлинность объекта.

При сравнении большинства других вещей в Python вы будете использовать !=.

25 голосов
/ 05 февраля 2010

Рассмотрим следующее:

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)
16 голосов
/ 05 февраля 2010

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

7 голосов
/ 05 февраля 2010
>>> () is ()
True
>>> 1 is 1
True
>>> (1,) == (1,)
True
>>> (1,) is (1,)
False
>>> a = (1,)
>>> b = a
>>> a is b
True

Некоторые объекты являются синглетонами, и поэтому is с ними эквивалентно ==. Большинство не.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...