Generalnie „someobj is None” jest lepsze niż „someobj == None”
Aaron Maenpaa
a co z pseudokodem, jeśli X to nie None? Albo X != None?
Charlie Parker
Odpowiedzi:
192
W pierwszym teście Python próbuje przekonwertować obiekt na boolwartość, jeśli jeszcze nią nie jest. Z grubsza pytamy obiekt: czy masz znaczenie, czy nie? Odbywa się to za pomocą następującego algorytmu:
Jeśli obiekt ma __nonzero__specjalną metodę (podobnie jak wbudowane numeryczne inti float), wywołuje tę metodę. Musi albo zwrócić boolwartość, która jest następnie używana bezpośrednio, albo intwartość, która jest uważana za Falserówną zero.
W przeciwnym razie, jeśli obiekt posiada __len__specjalną metodę (jak zrobić Zabudowy kontenerowe, list, dict, set, tuple, ...), wywołuje tę metodę, zważywszy pojemnik Falsejeśli jest pusta (długość wynosi zero).
W przeciwnym razie obiekt jest brany pod uwagę, Truechyba że Nonew takim przypadku jest brany pod uwagę False.
W drugim teście obiekt jest porównywany pod kątem równości z None. Tutaj pytamy obiekt: „Czy jesteś równy tej innej wartości?” Odbywa się to za pomocą następującego algorytmu:
Jeśli obiekt ma __eq__metodę, jest wywoływany, a wartość zwracana jest następnie konwertowana na boolwartość i używana do określenia wyniku if.
W przeciwnym razie, jeśli obiekt ma __cmp__metodę, jest wywoływany. Ta funkcja musi zwrócić intwskazanie kolejności dwóch obiektów ( -1if self < other, 0if self == other, +1if self > other).
W przeciwnym razie obiekty są porównywane pod kątem tożsamości (tj. Odnoszą się do tego samego obiektu, który może być testowany przez isoperatora).
Istnieje możliwość innego testu przy użyciu isoperatora. Pytalibyśmy obiekt: „Czy jesteś tym konkretnym obiektem?”
Generalnie radziłbym użyć pierwszego testu z wartościami nienumerycznymi, użyć testu równości, gdy chcesz porównać obiekty o tej samej naturze (dwa łańcuchy, dwie liczby, ...) i sprawdzić tożsamość tylko wtedy, gdy przy użyciu wartości wartowniczych ( Noneco oznacza, że nie zainicjowano pola członkowskiego na przykład lub podczas korzystania getattrz __getitem__metod lub ).
Chociaż technicznie poprawne, nie wyjaśnia to, że krotki, listy, dykty, ciągi, unicodes, int, float, itp. Mają wartość niezerową . O wiele bardziej powszechne jest poleganie na wartości prawdziwości typu wbudowanego niż na niestandardowej metodzie niezerowej .
ddaa,
52
W rzeczywistości są to obie słabe praktyki. Dawno, dawno temu uznano, że od niechcenia żadne i fałsz nie będą traktowane jako podobne. Jednak od czasu Pythona 2.2 nie jest to najlepsza zasada.
Po pierwsze, kiedy wykonujesz test if xlub if not xrodzaj testu, Python musi niejawnie przekonwertować xna wartość logiczną. Reguły tej boolfunkcji opisują wiele rzeczy, które są fałszywe; wszystko inne jest prawdą. Jeśli wartość x nie była właściwie logiczna na początku, ta niejawna konwersja nie jest tak naprawdę najlepszym sposobem na powiedzenie rzeczy.
Przed Pythonem 2.2 nie było funkcji bool, więc było to jeszcze mniej jasne.
Po drugie, tak naprawdę nie powinieneś testować == None. Powinieneś użyć is Nonei is not None.
- Comparisons to singletons like None should always be done with'is'or'is not', never the equality operators.
Also, beware of writing "if x" when you really mean "if x is not None"
-- e.g. when testing whether a variable or argument that defaults to
None was set to some other value. The other value might have a type
(such as a container) that could be false in a boolean context!
Ile jest singletonów? Pięć: None, True, False, NotImplementedi Ellipsis. Ponieważ jest mało prawdopodobne, że użyjesz NotImplementedlub Ellipsis, i nigdy byś tego nie powiedział if x is True(ponieważ if xjest po prostu o wiele bardziej przejrzysty), będziesz testować tylko None.
Druga forma to zdecydowanie niezła praktyka. PEP 8 zaleca dwukrotne użycie if x . Najpierw dla sekwencji (zamiast używać len), a następnie dla True i False (zamiast używać is). Praktycznie cały kod Pythona, który widziałem, używa if x, a jeśli nie x.
Antti Rasinen,
36
Ponieważ Nonenie jest to jedyna rzecz, która jest uważana za fałszywą.
ifnotFalse:
print"False is false."ifnot0:
print"0 is false."ifnot []:
print"An empty list is false."ifnot ():
print"An empty tuple is false."ifnot {}:
print"An empty dict is false."ifnot"":
print"An empty string is false."
False, 0, (), [], {}I ""są różne od None, dzięki czemu dwa fragmenty kodu są nie równoważne.
Ponadto weź pod uwagę następujące kwestie:
>>> False == 0True>>> False == ()
False
if object:to nie sprawdzian równość. 0, (), [], None, {}, Itd. Są bardzo różne od siebie, ale wszystkie one ocenić False.
Na tym polega „magia” wyrażeń zwierających, takich jak:
Jeśli chodzi o twoje ostatnie pytanie, są one równoważne.
Sylvain Defresne,
I oba są niepoprawne, ponieważ „” jest fałszywe. Drugi powinien brzmieć „(„ ”,) lub („ s ”,)”. W każdym razie, nowoczesne wersje Pythona mają właściwy operator trójskładnikowy. Ten podatny na błędy hack powinien zostać usunięty.
__nonzero__ metoda spam zostanie wywołany. Z podręcznika Pythona:
__nonzero__ ( self ) Wywoływana w celu zaimplementowania testowania wartości prawdy i wbudowanej operacji bool (); powinna zwracać False lub True, lub ich odpowiedniki w postaci liczb całkowitych 0 lub 1. Gdy ta metoda nie jest zdefiniowana, wywoływana jest funkcja __len __ (), jeśli została zdefiniowana (patrz poniżej). Jeśli klasa nie definiuje ani __len __ (), ani __nonzero __ (), wszystkie jej instancje są uznawane za prawdziwe.
Jeśli zapytasz
if spam == None:
print"Sorry. No SPAM here either."
__eq__ metoda spam zostanie wywołany z argumentem Żaden .
Aby być absolutnie poprawnym, drugi sprawdza -equality- z wartością None ... „someobj is None” sprawdza tożsamość.
Matthew Trevor,
0
Po pierwsze, pierwszy przykład jest krótszy i ładniejszy. Podobnie jak w innych postach, to, co wybierzesz, zależy również od tego, co naprawdę chcesz zrobić z porównaniem.
Osobiście wybrałem spójne podejście w różnych językach: robię to if (var)(lub równoważne) tylko wtedy, gdy var jest zadeklarowane jako logiczne (lub zdefiniowane jako takie, w C nie mamy określonego typu). Nawet poprzedzam te zmienne przedrostkiem b(tak byłoby w bVarrzeczywistości), aby mieć pewność, że przypadkowo nie użyję tutaj innego typu.
Nie lubię niejawnego rzutowania na boolean, tym bardziej, gdy istnieje wiele złożonych reguł.
Oczywiście ludzie się nie zgodzą. Niektórzy idą dalej, widzę if (bVar == true)w kodzie Java w mojej pracy (zbyt zbędny jak na mój gust!), Inni uwielbiają zbyt zwartą składnię, idą while (line = getNextLine())(zbyt niejednoznaczne dla mnie).
X != None
?Odpowiedzi:
W pierwszym teście Python próbuje przekonwertować obiekt na
bool
wartość, jeśli jeszcze nią nie jest. Z grubsza pytamy obiekt: czy masz znaczenie, czy nie? Odbywa się to za pomocą następującego algorytmu:Jeśli obiekt ma
__nonzero__
specjalną metodę (podobnie jak wbudowane numeryczneint
ifloat
), wywołuje tę metodę. Musi albo zwrócićbool
wartość, która jest następnie używana bezpośrednio, alboint
wartość, która jest uważana zaFalse
równą zero.W przeciwnym razie, jeśli obiekt posiada
__len__
specjalną metodę (jak zrobić Zabudowy kontenerowe,list
,dict
,set
,tuple
, ...), wywołuje tę metodę, zważywszy pojemnikFalse
jeśli jest pusta (długość wynosi zero).W przeciwnym razie obiekt jest brany pod uwagę,
True
chyba żeNone
w takim przypadku jest brany pod uwagęFalse
.W drugim teście obiekt jest porównywany pod kątem równości z
None
. Tutaj pytamy obiekt: „Czy jesteś równy tej innej wartości?” Odbywa się to za pomocą następującego algorytmu:Jeśli obiekt ma
__eq__
metodę, jest wywoływany, a wartość zwracana jest następnie konwertowana nabool
wartość i używana do określenia wynikuif
.W przeciwnym razie, jeśli obiekt ma
__cmp__
metodę, jest wywoływany. Ta funkcja musi zwrócićint
wskazanie kolejności dwóch obiektów (-1
ifself < other
,0
ifself == other
,+1
ifself > other
).W przeciwnym razie obiekty są porównywane pod kątem tożsamości (tj. Odnoszą się do tego samego obiektu, który może być testowany przez
is
operatora).Istnieje możliwość innego testu przy użyciu
is
operatora. Pytalibyśmy obiekt: „Czy jesteś tym konkretnym obiektem?”Generalnie radziłbym użyć pierwszego testu z wartościami nienumerycznymi, użyć testu równości, gdy chcesz porównać obiekty o tej samej naturze (dwa łańcuchy, dwie liczby, ...) i sprawdzić tożsamość tylko wtedy, gdy przy użyciu wartości wartowniczych (
None
co oznacza, że nie zainicjowano pola członkowskiego na przykład lub podczas korzystaniagetattr
z__getitem__
metod lub ).Podsumowując, mamy:
>>> class A(object): ... def __repr__(self): ... return 'A()' ... def __nonzero__(self): ... return False >>> class B(object): ... def __repr__(self): ... return 'B()' ... def __len__(self): ... return 0 >>> class C(object): ... def __repr__(self): ... return 'C()' ... def __cmp__(self, other): ... return 0 >>> class D(object): ... def __repr__(self): ... return 'D()' ... def __eq__(self, other): ... return True >>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]: ... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \ ... (repr(obj), bool(obj), obj == None, obj is None) '': bool(obj) -> False, obj == None -> False, obj is None -> False (): bool(obj) -> False, obj == None -> False, obj is None -> False []: bool(obj) -> False, obj == None -> False, obj is None -> False {}: bool(obj) -> False, obj == None -> False, obj is None -> False 0: bool(obj) -> False, obj == None -> False, obj is None -> False 0.0: bool(obj) -> False, obj == None -> False, obj is None -> False A(): bool(obj) -> False, obj == None -> False, obj is None -> False B(): bool(obj) -> False, obj == None -> False, obj is None -> False C(): bool(obj) -> True, obj == None -> True, obj is None -> False D(): bool(obj) -> True, obj == None -> True, obj is None -> False None: bool(obj) -> False, obj == None -> True, obj is None -> True
źródło
W rzeczywistości są to obie słabe praktyki. Dawno, dawno temu uznano, że od niechcenia żadne i fałsz nie będą traktowane jako podobne. Jednak od czasu Pythona 2.2 nie jest to najlepsza zasada.
Po pierwsze, kiedy wykonujesz test
if x
lubif not x
rodzaj testu, Python musi niejawnie przekonwertowaćx
na wartość logiczną. Reguły tejbool
funkcji opisują wiele rzeczy, które są fałszywe; wszystko inne jest prawdą. Jeśli wartość x nie była właściwie logiczna na początku, ta niejawna konwersja nie jest tak naprawdę najlepszym sposobem na powiedzenie rzeczy.Przed Pythonem 2.2 nie było funkcji bool, więc było to jeszcze mniej jasne.
Po drugie, tak naprawdę nie powinieneś testować
== None
. Powinieneś użyćis None
iis not None
.Zobacz PEP 8, Style Guide for Python Code .
Ile jest singletonów? Pięć:
None
,True
,False
,NotImplemented
iEllipsis
. Ponieważ jest mało prawdopodobne, że użyjeszNotImplemented
lubEllipsis
, i nigdy byś tego nie powiedziałif x is True
(ponieważif x
jest po prostu o wiele bardziej przejrzysty), będziesz testować tylkoNone
.źródło
Ponieważ
None
nie jest to jedyna rzecz, która jest uważana za fałszywą.if not False: print "False is false." if not 0: print "0 is false." if not []: print "An empty list is false." if not (): print "An empty tuple is false." if not {}: print "An empty dict is false." if not "": print "An empty string is false."
False
,0
,()
,[]
,{}
I""
są różne odNone
, dzięki czemu dwa fragmenty kodu są nie równoważne.Ponadto weź pod uwagę następujące kwestie:
>>> False == 0 True >>> False == () False
if object:
to nie sprawdzian równość.0
,()
,[]
,None
,{}
, Itd. Są bardzo różne od siebie, ale wszystkie one ocenić False.Na tym polega „magia” wyrażeń zwierających, takich jak:
foo = bar and spam or eggs
co jest skrótem dla:
if bar: foo = spam else: foo = eggs
chociaż naprawdę powinieneś napisać:
foo = spam if bar else egg
źródło
PEP 8 - Style Guide for Python Code, które zaleca użycie jest lub nie, jeśli testujesz na brak
Z drugiej strony, jeśli testujesz dla więcej niż Brak, powinieneś użyć operatora boolowskiego.
źródło
Jeśli zapytasz
if not spam: print "Sorry. No SPAM."
__nonzero__ metoda spam zostanie wywołany. Z podręcznika Pythona:
Jeśli zapytasz
if spam == None: print "Sorry. No SPAM here either."
__eq__ metoda spam zostanie wywołany z argumentem Żaden .
Aby uzyskać więcej informacji na temat możliwości dostosowywania, zapoznaj się z dokumentacją Pythona pod adresem https://docs.python.org/reference/datamodel.html#basic-customization
źródło
Te dwa porównania służą różnym celom. Pierwsza sprawdza wartość logiczną czegoś, druga sprawdza tożsamość z wartością Brak.
źródło
Po pierwsze, pierwszy przykład jest krótszy i ładniejszy. Podobnie jak w innych postach, to, co wybierzesz, zależy również od tego, co naprawdę chcesz zrobić z porównaniem.
źródło
Odpowiedź brzmi: „to zależy”.
Używam pierwszego przykładu, jeśli uznam, że 0, "", [] i False (lista nie jest wyczerpująca) są równoważne z None w tym kontekście.
źródło
Osobiście wybrałem spójne podejście w różnych językach: robię to
if (var)
(lub równoważne) tylko wtedy, gdy var jest zadeklarowane jako logiczne (lub zdefiniowane jako takie, w C nie mamy określonego typu). Nawet poprzedzam te zmienne przedrostkiemb
(tak byłoby wbVar
rzeczywistości), aby mieć pewność, że przypadkowo nie użyję tutaj innego typu.Nie lubię niejawnego rzutowania na boolean, tym bardziej, gdy istnieje wiele złożonych reguł.
Oczywiście ludzie się nie zgodzą. Niektórzy idą dalej, widzę
if (bVar == true)
w kodzie Java w mojej pracy (zbyt zbędny jak na mój gust!), Inni uwielbiają zbyt zwartą składnię, idąwhile (line = getNextLine())
(zbyt niejednoznaczne dla mnie).źródło