У коментарі до цього питання я побачив твердження, яке рекомендував використовувати
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 ==
. Python - ==
це як у 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__
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
. Вони мають однакову марку і модель. Однак вони ні мають однакових даних, ні є однаковим об'єктом у пам'яті. Однак, коли ми порівнюємо їх, ми хочемо, щоб вони порівняли рівні. Тут відбувається те, що об'єкт "Монітор" реалізував __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,) >>> b = a >>> а - б Правда
Деякі об'єкти є одинаковими, і, таким чином, is
з ними рівносильно ==
. Більшість - ні.
()
і 1
по суті не є однотонними.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) та порожні кортежі є одинаковими. Дійсно, це не зафіксовано і не гарантується, але навряд чи це зміниться.