Сравнение Python None: следует ли использовать is или ==?

Мой редактор предупреждает меня, когда я сравниваю my_var == None, но не предупреждает, когда я использую my_var is None.

Я провел тест в оболочке Python и определил, что оба являются допустимым синтаксисом, но мой редактор, похоже, говорит, что my_var is None предпочтительнее.

Так ли это, и если да, то почему?


person Clay Wardell    schedule 09.01.2013    source источник
comment
В PEP 8 где-то говорится, что вы должны сравнивать с одиночками, используя is - python. org / dev / peps / pep-0008 / # программирование-рекомендации   -  person Volatility    schedule 10.01.2013
comment
Этот плакат рассказывает о Python 3, а мой вопрос о Python 2.x. Я не уверен, что это достаточно большая разница, чтобы гарантировать, что оба остались, но я отредактировал вопрос, включив это на всякий случай.   -  person Clay Wardell    schedule 10.01.2013
comment
Не думаю, что этот вопрос действительно повторяется. Другой был о == vs в целом, этот о None в частности.   -  person I. J. Kennedy    schedule 05.05.2014


Ответы (6)


Резюме:

Используйте is, если хотите проверить идентичность объекта (например, проверяя, является ли var None). Используйте ==, если хотите проверить равенство (например, var равно 3?).

Объяснение:

У вас могут быть собственные классы, где my_var == None вернет True

e.g:

class Negator(object):
    def __eq__(self,other):
        return not other

thing = Negator()
print thing == None    #True
print thing is None    #False

is проверяет объект идентичность. Есть только 1 объект None, поэтому, когда вы делаете my_var is None, вы проверяете, действительно ли они являются одним и тем же объектом (а не только эквивалентными объектами)

Другими словами, == - это проверка на эквивалентность (которая определяется от объекта к объекту), тогда как is проверяет идентичность объекта:

lst = [1,2,3]
lst == lst[:]  # This is True since the lists are "equivalent"
lst is lst[:]  # This is False since they're actually different objects
person mgilson    schedule 09.01.2013
comment
Вы имеете в виду, что перегрузка оператора == всегда возвращает True по сравнению с None? - person Clay Wardell; 10.01.2013
comment
Когда is None отличается от == None? - person Blender; 10.01.2013
comment
@Blender В упомянутом случае. __eq__ можно определить любым способом, но поведение is не может быть изменено так легко. - person Lev Levitsky; 10.01.2013
comment
Ах, последний пример с lst прояснил это. Спасибо. - person Clay Wardell; 10.01.2013
comment
@LevLevitsky: Одним из примеров использования Mython было расширение протоколов, так что любой оператор может быть перегружен, даже is. После комментария к спискам он изменил это на… даже is (но только если ты ненормальный). - person abarnert; 10.01.2013
comment
+1, но было бы даже лучше, если бы этот ответ включал ссылку на PEP 8, которую делают другие (а также объяснение, почему решение, лежащее в основе PEP 8, имеет смысл, что уже есть). - person abarnert; 10.01.2013
comment
@abarnert - Я даже не знал, что PEP 8 дал здесь рекомендацию. Дело в том, что это разные операторы, которые делают разные вещи. Могут быть случаи, когда object == None на самом деле является правильной идиомой (хотя я не могу придумать ни одной из них в голове). Вам просто нужно знать, что вы делаете. - person mgilson; 10.01.2013
comment
@LevLevitsky Я всегда использую мнемонику, чтобы помнить, что is сравнивает адрес, а == сравнивает значение. Я ни разу не ошибся, используя эту мнемонику. Таким образом, изменение реализации is похоже на подделку другого адреса. - person John Strood; 04.01.2019
comment
@mgilson Если вы используете другие языки или, например, Java, a == null означает, что значение (или значение указателя) a на самом деле является просто специальным литералом с именем null, который не является ни экземпляром, ни значением, сравнимым с чем-либо. В Python этого нет, а None - это одноэлементный экземпляр класса NoneType. a == None было бы просто сумасшествием, потому что я мог бы переопределить __eq__ и сделать его равным None каждый раз, даже если это не так. Между тем a is None просто пытается приравнять адрес одноэлементного объекта, который должен представлять все нулевые объекты в мире. - person John Strood; 04.01.2019
comment
@mgilson Итак, вы видите, что идиоматически в Python a is None имеет более правильный смысл, чем a == None. - person John Strood; 04.01.2019
comment
@JohnStrood Python id(a) == id(None) эквивалентен как a is None, так и a == null в Java. Это не имеет ничего общего с абсолютной правильностью. В большинстве случаев вы захотите использовать is. Это никоим образом не означает, что нет случаев, когда == имеет более концептуальный смысл. Неспособность думать об одном - это просто недостаток воображения, а не правило вселенной. - person Mad Physicist; 25.04.2020

is обычно предпочтительнее при сравнении произвольных объектов с одиночными объектами, такими как None, потому что это быстрее и более предсказуемо. is всегда сравнивает по идентичности объекта, тогда как то, что == будет делать, зависит от точного типа операндов и даже от их порядка.

Эта рекомендация поддерживается PEP 8, который прямо заявляет, что" сравнения с одиночными версиями, такими как None, всегда должны выполняться с is или is not, а не с операторы равенства ".

person user4815162342    schedule 09.01.2013
comment
Спасибо, что разместили это; принятый ответ содержит некоторые интересные моменты, но ваш ответ на вопрос гораздо более прямолинейный. - person Luke Davis; 26.04.2017
comment
Кажется странным полагаться на то, что по сути является деталью реализации. Почему меня должно волновать количество экземпляров NoneType? - person BallpointBen; 17.01.2019
comment
@BallpointBen Потому что это не деталь реализации - есть только один объект None под глобальной константой None. Во всяком случае, NoneType - это деталь реализации, потому что синглтон None должен иметь некоторый тип. (Тот факт, что вы не можете создавать экземпляры этого типа, является хорошим признаком того, что его один экземпляр предназначен для синглтона.) - person user4815162342; 17.01.2019
comment
@BallpointBen Я думаю, что ключевым моментом является то, что Python обладает четкой концепцией идентичности объекта. Если вы хотите проверить, сравнивается ли объект равным с None, непременно используйте obj == None. Если вы хотите проверить, является ли объект None, используйте obj is None. Суть рекомендации PEP 8 (и этого ответа) заключается в том, что большинство людей хотят последнего, когда хотят проверить отсутствие, и это также оказывается быстрее и понятнее. - person user4815162342; 22.01.2019
comment
None также отличается от кэшированных объектов, таких как 0 и других небольших целых чисел, где кеширование действительно является деталью реализации. Разница в том, что целое число имеет внутреннее значение, которое определяет его свойства, и его можно вычислить. С другой стороны, None вообще не имеет состояния, важна только его идентичность, которая делает его особенным. - person user4815162342; 22.01.2019

PEP 8 определяет, что при сравнении синглтонов лучше использовать оператор is.

person Thorsten Kranz    schedule 09.01.2013

Я недавно столкнулся с тем, где это может пойти не так.

import numpy as np
nparray = np.arange(4)

# Works
def foo_is(x=None):
    if x is not None:
        print(x[1])

foo_is()
foo_is(nparray)

# Code below raises 
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def foo_eq(x=None):
    if x != None:
        print(x[1])

foo_eq()
foo_eq(nparray)

Я создал функцию, которая необязательно принимает массив numpy в качестве аргумента и изменяется раньше, если он включен. Если я проверю его включение с помощью операторов неравенства !=, это вызовет ошибку ValueError (см. Код выше). Если я использую is not none, код работает правильно.

person Danferno    schedule 09.04.2021

Другой случай, когда == отличается от is. Когда вы извлекаете информацию из базы данных и проверяете, существует ли значение, результатом будет либо значение, либо None.

Посмотрите на if и else ниже. Работает только тогда, когда база данных возвращает None. Если вместо этого вы поставите ==, оператор if не будет работать, он перейдет прямо к else, даже если результатом будет None. Надеюсь, я ясно выражаюсь.

conn = sqlite3.connect('test.db')
c = conn.cursor()
row = itemID_box.get()

# pull data to be logged so that the deletion is recorded
query = "SELECT itemID, item, description FROM items WHERE itemID LIKE '%" + row + "%'"
c.execute(query)
result = c.fetchone()

if result is None:
    # log the deletion in the app.log file
    logging = logger('Error')
    logging.info(f'The deletion of {row} failed.')
    messagebox.showwarning("Warning", "The record number is invalid")
else:
    # execute the deletion
    c.execute("DELETE from items WHERE itemID = " + row)
    itemID_box.delete(0, tk.END)
    messagebox.showinfo("Warning", "The record has been deleted")
    conn.commit()
    conn.close()
person Community    schedule 26.06.2021

Возьмем, к примеру, функцию печати. Смотри сюда:

print(print())
print(None)

Оба вывода None:

None
None

is относится к действительной вещи, независимо от того, являются ли они объектом - нет. Печать не объект нет.

print(None is print)
print(None is None)

Теперь мы получаем желаемый результат.

False
True

PEP 8 также упоминает об этом, говоря, что сравнения с одиночными числами, такими как None, всегда должны выполняться с использованием is или is or is, но никогда с операторами равенства.

is тоже быстрее.

person Aarav Dave    schedule 18.05.2021
comment
Я думаю, что цитата из PEP8 - правильный ответ, возможно, стоит представить именно это. Я не понимаю сути вашего примера. - person BobHy; 18.05.2021
comment
Спрашивающий сказал: «Если да, и почему», вот почему, чтобы избежать ошибок. PEP8 - это побочная вещь и руководство по форматированию. Но я все равно поставил это, чтобы другие могли сослаться. - person Aarav Dave; 19.05.2021
comment
Но ваш пример неверен. Выражение print( None is print()) отображает True (в моей копии Python 3.8.6). Я бы ответил на вопрос, если да, то почему именно PEP8 рекомендует эту идиому, а редактор автора вопроса применяет эту рекомендацию. - person BobHy; 20.05.2021
comment
Ах да, прости. Было бы None is print. Я исправлю это сразу. - person Aarav Dave; 22.05.2021