Ответ 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 вы будете использовать !=
.