Есть ли разница между «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
Brendan
источник
51
Вы можете добавить, что None - это синглтон, поэтому «None is None» - это всегда True.
Э-Удовлетворение
43
И вы можете добавить, что isоператор не может быть настроен (перегружен определяемым пользователем классом).
Мартино
@study Метод __eq__(self)- это специальный встроенный метод, который определяет, как ==обрабатывается при использовании объекта Python. Здесь мы переопределили это так, что когда ==оно используется для объектов типа, Fooоно всегда возвращает true. Для isоператора не существует эквивалентного метода, и поэтому поведение isнельзя изменить таким же образом.
Брендан
Это потому, что определение класса foo не имеет конструктора, то есть функции init ?
учеба
49

Вы можете прочитать этот объект идентичности и эквивалентности .

Оператор «is» используется для идентификации объекта, он проверяет, ссылаются ли объекты на один и тот же экземпляр (тот же адрес в памяти).

И выражение «==» относится к равенству (то же значение).

Borrego
источник
Хммм, я думаю, что ваша ссылка изменилась, если вы не интересовались, как вызывать внешние функции из python
Пэт
Я только что попробовал a=1;b=1;print(a is b) # True. Есть идеи, почему они a is bоказываются правдой, даже если они кажутся двумя разными объектами (разные адреса в памяти)?
Джонни Чиу
24

Слово предостережения:

if foo:
  # do something

Это не то же самое, что:

if x is not None:
  # do something

Первый из них является тестом логического значения и может принимать значение false в разных контекстах. Есть несколько вещей, которые представляют ложь в тестах логических значений, например, пустые контейнеры, логические значения. Никто также не оценивает ложь в этой ситуации, но другие вещи тоже.

Тендай Мавуше
источник
12

(ob1 is ob2) равно (id(ob1) == id(ob2))

Николай Харечко
источник
6
... но (ob is ob2) намного быстрее. Timeit говорит, что «(a - это b)» - 0,0365 мксек на цикл, а «(id (a) == id (b))» - 0,153 мксек на цикл. В 4,2 раза быстрее!
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.

truppo
источник
8

Нет никакой разницы, потому что объекты, которые идентичны, конечно, будут равны. Однако в PEP 8 четко указано, что вы должны использовать is:

Сравнения с синглетами, такими как None, всегда должны выполняться с операторами is или not, а не с операторами равенства.

Тийс ван Дин
источник
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
ChillarAnand
источник
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, скажите «если x равен None:».

Грэм Перроу
источник
Проверка на пустые строки / списки с помощью «if var» является предпочтительным способом. Булево преобразование хорошо определено, и это меньше кода, который даже работает лучше. Нет причин делать "если len (mylist) == 0", например.
Труппо
Неправильно. Предположим, что foo = "". Затем if fooвернет false и комментарий #foo is Noneбудет неверным.
Blokeley
Примечание для downvoters - мой ответ цитирует ответ, который с тех пор был удален, и не согласен с ним. Если вам не нравится код в моем ответе, вам нужно поднять голос . :-)
Грэм Перроу
2

Еще несколько деталей:

  1. Предложение isфактически проверяет, objectнаходятся ли два элемента в одной и той же ячейке памяти или нет. то есть указывают ли они на одну и ту же ячейку памяти и имеют ли они одинаковое значение 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
@ThiefMaster ли ответ имеет тенденцию быть неправильно истолкованным? Хотя, прочитав его снова, я не смог найти его (с упоминанием «некоторых исключений»). Ваше утверждение относится только к строкам, а не intверно?
Кровоточащие пальцы
Не совсем, но так как у вас есть этот пример в вашем ответе, я подумал, что было бы неплохо предупредить пользователей, что на самом деле это плохая идея. Может быть, добавить что-то вроде "# cpython specific / not Guaranteed" за этой строкой ...
ThiefMaster
1

Вывод Джона Мачина о том, что он Noneявляется единичным, является заключением, подкрепленным этим кодексом.

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

Так Noneкак это единственный, x == Noneи x is Noneбудет иметь тот же результат. Однако, по моему эстетическому мнению, x == Noneлучше всего.

ncmathsadist
источник
2
Я не согласен с мнением в конце этого ответа. При явном сравнении с ним обычно подразумевается, что рассматриваемый объект является именно Noneобъектом. Для сравнения, редко можно увидеть, что 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
Акс
источник