Python!= Операция против "не"

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

result is not None

против

result != None

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

Ответ 1

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

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

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

Ответ 2

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

Определения

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

>>> 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 a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

Примечание. Я использую строки Юникода здесь, потому что 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__ on 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 вы будете использовать !=.

Ответ 3

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

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)

Ответ 4

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

Ответ 5

>>> () is ()
True
>>> 1 is 1
True
>>> (1,) == (1,)
True
>>> (1,) is (1,)
False
>>> a = (1,)
>>> b = a
>>> a is b
True

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

Ответ 6

просто хочу знать, правильно ли я понимаю

  • так это б вполне буквально тестирование, если "а" это то же самое, как "Ъ"

  • и a == b просто проверяет, является ли 'a' РАВНЫМ 'b'