Python Няма сравнение: трябва ли да използвам 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/#programming-recommendations   -  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 id(a) == id(None) на Python е еквивалентен както на 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 (и на този отговор) е, че повечето хора искат последното, когато искат да проверят за None, а също така се случва да е по-бързо и по-ясно. - 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

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

Вижте 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

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

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

Сега получаваме желания резултат.

False
True

PEP 8 също споменава това, като казва, че сравненията със сингълтони като None винаги трябва да се правят с is или not, никога с операторите за равенство.

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 препоръчва този идиом, а редакторът на asker налага тази препоръка. - person BobHy; 20.05.2021
comment
О, да, съжалявам. Би било None is print. Ще го оправя веднага. - person Aarav Dave; 22.05.2021