У коментарі до цього питання я побачив твердження, яке рекомендував використовувати
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) та порожні кортежі є одинаковими. Дійсно, це не зафіксовано і не гарантується, але навряд чи це зміниться.