Чи є різниця між "foo is None" і "foo == None"?


217

Чи є різниця між:

if foo is None: pass

і

if foo == None: pass

Конвенція, яку я бачив у більшості кодів Python (і код, який я сам пишу), є першим, але я нещодавно натрапив на код, який використовує останній. Жоден екземпляр (і єдиний екземпляр, IIRC) NoneType, тому це не має значення, правда? Чи існують обставини, за яких це може бути?

Відповіді:


253

isзавжди повертається, Trueякщо порівнює один і той же екземпляр об'єкта

Тоді як ==в кінцевому рахунку визначається __eq__()метод

тобто


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

51
Ви можете додати, що "None" є однотонним, тому "None є None" завжди є "True".
e-satis

43
І ви можете додати, що isоператор не може бути налаштований (перевантажений визначеним користувачем класом).
мартіно

@study Метод __eq__(self)- це спеціальний вбудований метод, який визначає, як ==обробляється при використанні об’єкта Python. Тут ми її перекрили, так що коли ==використовується на об'єктах типу, Fooвона завжди повертає true. Не існує еквівалентного методу для isоператора, і тому поведінку isне можна змінити однаково.
Брендан

Це тому, що визначення класу foo не має конструктора, тобто функції init ?
дослідження

49

Ви можете прочитати ідентичність та еквівалентність цього об'єкта .

Вираз "є" використовується для ідентичності об'єкта, він перевіряє, чи об'єкти посилаються на один і той же екземпляр (та сама адреса в пам'яті).

І вислів '==' відноситься до рівності (однакове значення).


Гммм, я думаю, що ваше посилання змінилося, якщо тільки вас не цікавило, як викликати зовнішні функції з python
Пт

Я просто спробував a=1;b=1;print(a is b) # True. Будь-яка ідея, чому a is bвиявляється правдивою, навіть якщо вони здаються двома різними об'єктами (різною адресою в пам'яті)?
Johnny Chiu

24

Слово обережності:

if foo:
  # do something

Хіба НЕ точно так же , як:

if x is not None:
  # do something

Перший є булевим значенням тесту і може оцінювати помилкове в різних контекстах. Існує ряд речей, які представляють помилки в булевих тестах значення, наприклад порожні контейнери, булеві значення. Жоден також не оцінює помилкове в цій ситуації, але інші речі теж роблять.


12

(ob1 is ob2) дорівнює (id(ob1) == id(ob2))


6
... але (ob є ob2) швидше на багато. Timeit каже, що "(a є b)" становить 0,0365 Usec на цикл, а "(id (a) == id (b))" 0,153 Usec на цикл. 4.2x швидше!
AKX

4
isверсія не потребує в виконанні функції, і не пошук атрибута пітона-інтерпретатора на всіх; перекладач може негайно відповісти, якщо ob1 є насправді ob2.
u0b34a0f6ae

17
Ні, це не є. {} is {}є хибним і id({}) == id({})може бути (і є в CPython) істинним. Дивіться stackoverflow.com/questions/3877230
Пьотр Доброгост

12

Причина foo is None- кращий спосіб полягає в тому, що ви можете обробляти об'єкт, який визначає його власний __eq__, і визначає, що об'єкт дорівнює None. Отже, завжди використовуйте, foo is Noneякщо вам потрібно перевірити, чи є це інфакт None.


8

Різниці немає, тому що об'єкти, які однакові, будуть, звичайно, однаковими. Однак PEP 8 чітко стверджує, що ви повинні використовувати is:

Порівняння одинакових, як None, завжди слід проводити з операторами рівності, ні, ні, ні.


7

isтести на ідентичність, а не на рівність. Для вашого твердження foo is nonePython просто порівнює адресу пам'яті об'єктів. Це означає, що ви задаєте питання "Чи маю я два імені для одного об'єкта?"

==з іншого боку, тести на рівність, визначені __eq__()методом. Це не хвилює ідентичність.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneє одиночним оператором. Так None is Noneзавжди правда.

In [101]: None is None
Out[101]: True

5

Для None не повинно бути різниці між рівністю (==) та ідентичністю (є). Мабуть, NoneType повертає ідентичність для рівності. Оскільки None - єдиний екземпляр, який ви можете зробити з NoneType (я думаю, це правда), дві операції однакові. Що стосується інших типів, це не завжди так. Наприклад:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Це буде друкувати "Рівно", оскільки списки мають операцію порівняння, яка не є поверненням ідентичності за замовчуванням.


5

@ Джейсон :

Я рекомендую використовувати щось більше за принципом

if foo:
    #foo isn't None
else:
    #foo is None

Мені не подобається використовувати "if foo:", якщо foo справді не представляє булевого значення (тобто 0 або 1). Якщо foo - це рядок або об'єкт чи щось інше, "if foo:" може спрацювати, але це виглядає як лінивий ярлик для мене. Якщо ви перевіряєте, чи x є None, скажіть "if x is None:".


Перевірка порожніх рядків / списків за допомогою "якщо var" є кращим способом. Булева конверсія чітко визначена, і менше код навіть краще. Немає причин робити "if len (mylist) == 0", наприклад.
truppo

Неправильно. Припустимо, foo = "". Тоді if fooповернеться помилковим, а коментар #foo is Noneневірним.
blokeley

Зверніть увагу на поточні моменти - моя відповідь наводить відповідь, яку з тих пір було видалено, і не згоден з нею. Якщо вам не сподобався код у моїй відповіді, вам потрібно подати заявку . :-)
Graeme Perrow

2

Ще кілька деталей:

  1. Цей isпункт фактично перевіряє, чи є два objects в одному місці пам'яті чи ні. тобто вони вказують на одне місце пам’яті і чи однакові id.

  2. Як наслідок 1, isгарантує, чи є, чи немає, два лексично представлені objects мають однакові атрибути (атрибути атрибутів ...) чи ні

  3. Інстанцірованія примітивних типів , таких як bool, int, string(з деяким винятком), NoneTypeщо має те ж значення завжди буде в тому ж місці пам'яті.

Напр

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

А оскільки NoneTypeможе мати лише один екземпляр себе в таблиці "перегляду" python, тому перший і останній є більш стилем програмування розробника, який написав код (можливо, для послідовності), а не маючи будь-якої тонкої логічної причини для вибирайте один над іншим.


2
Усі, хто читає це: НЕ використовуйте some_string is "bar"для порівняння рядків ВСЕ. ЦЕ НЕ Є ОДНОГО ПРИЙМОГО ПРИЧИНИ, і це БУДЕ НАРУШЕНО, коли Ви цього не очікуєте. Справа в тому, що вона працює часто - це просто тому, що CPython знає, що було б нерозумно створювати два незмінні об'єкти, що мають однаковий вміст. Але все-таки це може статися.
ThiefMaster

@TentistMaster чи відповідає відповідь неправильним тлумаченням? Хоча, прочитавши його ще раз, я не зміг виявити, що це було (із згадкою про "деякі винятки"). Ваше твердження стосується лише рядків, а ні int, правда?
Кровотечі пальці

Насправді, але, оскільки у вас є такий приклад у вашій відповіді, я подумав, що було б корисно попередити користувачів, що насправді використовувати це погано. Можливо, додайте щось схоже на "# cpython specific / notuarante" за цим рядком ...
ThiefMaster

1

Висновок Джона Макіна, що Noneє одинаком, - це висновок, підкріплений цим кодом.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Так Noneяк синглтон, x == Noneі x is Noneмав би той самий результат. Однак, на мою естетичну думку, x == Noneнайкраще.


2
Я не згоден з думкою в кінці цієї відповіді. Якщо явно порівнювати їх із жодним, зазвичай передбачається, що саме цей об'єкт є саме Noneоб'єктом. Для порівняння, рідко бачиться, що жоден не використовується в будь-якому іншому контексті, за винятком того, що він подібний до Falseінших значень, що є правдою. У цих випадках ідіоматичніше робити щось на кшталтif x: pass
SingleNegationElimination

0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.