Gibt es einen Unterschied zwischen "foo is None" und "foo == None"?

217

Gibt es einen Unterschied zwischen:

if foo is None: pass

und

if foo == None: pass

Die Konvention, die ich in den meisten Python-Codes gesehen habe (und den Code, den ich selbst schreibe), ist die erstere, aber ich bin kürzlich auf Code gestoßen, der den letzteren verwendet. None ist eine Instanz (und die einzige Instanz, IIRC) von NoneType, also sollte es keine Rolle spielen, oder? Gibt es Umstände, unter denen dies der Fall sein könnte?

Joe Shaw
quelle

Antworten:

253

isGibt immer zurück, Truewenn dieselbe Objektinstanz verglichen wird

Während ==wird letztendlich durch die __eq__()Methode bestimmt

dh


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

>>> f = Foo()
>>> f == None
True
>>> f is None
False
Brendan
quelle
51
Möglicherweise möchten Sie hinzufügen, dass None ein Singleton ist, sodass "None is None" immer True ist.
E-Satis
43
Möglicherweise möchten Sie hinzufügen, dass der isOperator nicht angepasst werden kann (überladen durch eine benutzerdefinierte Klasse).
Martineau
@study Die Methode __eq__(self)ist eine spezielle integrierte Methode, die bestimmt, wie ==mit einem Python-Objekt umgegangen wird . Hier haben wir es überschrieben, damit es bei ==Verwendung für Objekte vom Typ Fooimmer true zurückgibt. Es gibt keine äquivalente Methode für den isOperator und daher kann das Verhalten von isnicht auf die gleiche Weise geändert werden.
Brendan
Liegt es daran, dass die Definition der foo-Klasse keinen Konstruktor hat, dh die init- Funktion?
Studie
49

Möglicherweise möchten Sie diese Objektidentität und -äquivalenz lesen .

Die Anweisung 'is' wird für die Objektidentität verwendet und prüft, ob Objekte auf dieselbe Instanz verweisen (gleiche Adresse im Speicher).

Und die '==' Anweisung bezieht sich auf Gleichheit (gleicher Wert).

Borrego
quelle
Hmmm, ich denke, Ihr Link hat sich geändert, es sei denn, Sie waren daran interessiert , externe Funktionen von Python aus aufzurufen
Pat
Ich habe es gerade versucht a=1;b=1;print(a is b) # True. Irgendeine Idee, warum a is bsich herausstellt, dass es wahr ist, selbst wenn es sich um zwei verschiedene Objekte handelt (unterschiedliche Adresse im Speicher)?
Johnny Chiu
24

Ein Wort der Vorsicht:

if foo:
  # do something

Ist nicht genau das gleiche wie:

if x is not None:
  # do something

Ersteres ist ein Boolescher Wertetest und kann in verschiedenen Kontexten als falsch bewertet werden. Es gibt eine Reihe von Dingen, die in einem Booleschen Wertestest falsch darstellen, z. B. leere Container oder Boolesche Werte. Keiner wird in dieser Situation ebenfalls als falsch bewertet, aber auch andere Dinge.

Tendayi Mawushe
quelle
12

(ob1 is ob2) gleich (id(ob1) == id(ob2))

Mykola Kharechko
quelle
6
... aber (ob ist ob2) ist viel schneller. Timeit sagt, "(a ist b)" ist 0,0365 usec pro Schleife und "(id (a) == id (b))" ist 0,153 usec pro Schleife. 4,2x schneller!
AKX
4
Die isVersion benötigt keinen Funktionsaufruf und überhaupt keine Suche nach Python-Interpreter-Attributen. Der Dolmetscher kann sofort antworten, ob ob1 tatsächlich ob2 ist.
u0b34a0f6ae
17
Nein, tut es nicht. {} is {}ist falsch und id({}) == id({})kann (und ist in CPython) wahr sein. Siehe stackoverflow.com/questions/3877230
Piotr Dobrogost
12

Der Grund dafür foo is Noneist, dass Sie möglicherweise ein Objekt behandeln, das sein eigenes __eq__definiert und das Objekt so definiert , dass es gleich None ist. Verwenden foo is NoneSie es also immer, wenn Sie sehen möchten, ob es infakt ist None.

Truppo
quelle
8

Es gibt keinen Unterschied, da identische Objekte natürlich gleich sind. In PEP 8 heißt es jedoch eindeutig, dass Sie Folgendes verwenden sollten is:

Vergleiche mit Singletons wie None sollten immer mit is oder is durchgeführt werden, niemals mit den Gleichheitsoperatoren.

Thijs van Dien
quelle
7

isIdentitätsprüfungen, nicht Gleichheit. Für Ihre Aussage foo is nonevergleicht Python einfach die Speicheradresse von Objekten. Es bedeutet, dass Sie die Frage stellen: "Habe ich zwei Namen für dasselbe Objekt?"

==andererseits Tests nach Gleichheit, wie durch die __eq__()Methode bestimmt. Identität ist ihm egal.

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

Noneist ein Singleton-Operator. So None is Noneist es immer wahr.

In [101]: None is None
Out[101]: True
ChillarAnand
quelle
5

Für None sollte es keinen Unterschied zwischen Gleichheit (==) und Identität (is) geben. Der NoneType gibt wahrscheinlich Identität für Gleichheit zurück. Da None die einzige Instanz ist, die Sie mit NoneType erstellen können (ich denke, das ist wahr), sind die beiden Operationen gleich. Bei anderen Typen ist dies nicht immer der Fall. Beispielsweise:

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

Dies würde "Gleich" ausgeben, da Listen eine Vergleichsoperation haben, die nicht die Standardrückgabe der Identität ist.

Stephen Pellicer
quelle
5

@ Jason :

Ich empfehle etwas mehr in der Art von

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

Ich mag es nicht, "if foo:" zu verwenden, es sei denn, foo repräsentiert wirklich einen booleschen Wert (dh 0 oder 1). Wenn foo eine Zeichenfolge oder ein Objekt oder etwas anderes ist, funktioniert "if foo:" möglicherweise, aber es sieht für mich nach einer faulen Verknüpfung aus. Wenn Sie überprüfen, ob x Keine ist, sagen Sie "Wenn x Keine ist:".

Graeme Perrow
quelle
Das Überprüfen auf leere Zeichenfolgen / Listen mit "if var" ist der bevorzugte Weg. Die boolesche Konvertierung ist gut definiert und es ist weniger Code, der sogar eine bessere Leistung erbringt. Kein Grund, zum Beispiel "if len (mylist) == 0" zu tun.
Truppo
Falsch. Angenommen, foo = "". Dann if foowird false zurückgegeben und der Kommentar #foo is Noneist falsch.
Blokeley
Hinweis für Downvoter - Meine Antwort zitiert eine Antwort, die inzwischen gelöscht wurde und damit nicht einverstanden ist. Wenn Ihnen der Code in meiner Antwort nicht gefällt, müssen Sie eine positive Bewertung abgeben . :-)
Graeme Perrow
2

Einige weitere Details:

  1. Die isKlausel prüft tatsächlich, ob sich die beiden objects am selben Speicherort befinden oder nicht. dh ob beide auf denselben Speicherort zeigen und denselben haben id.

  2. Als Konsequenz von 1 wird issichergestellt, ob die beiden lexikalisch dargestellten objects identische Attribute (Attribute von Attributen ...) haben oder nicht

  3. Instanziierung von primitiven Typen wie bool, int, string(mit einigen Ausnahmen), NoneTypewird in der gleichen Speicherstelle immer einen gleichen Wert aufweist.

Z.B

>>> 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

Und da NoneTypenur eine Instanz von sich selbst in der "Nachschlagetabelle" des Pythons enthalten sein kann, sind erstere und letztere eher ein Programmierstil des Entwicklers, der den Code geschrieben hat (möglicherweise aus Gründen der Konsistenz), als einen subtilen logischen Grund dafür wähle eins über das andere.

Blutende Finger
quelle
2
Jeder, der dies liest: NIEMALS verwenden some_string is "bar", um Zeichenfolgen zu vergleichen. Es gibt keinen einzigen akzeptablen Grund dafür und es wird brechen, wenn Sie es nicht erwarten. Die Tatsache, dass es oft funktioniert, liegt einfach daran, dass CPython weiß, dass es dumm wäre, zwei unveränderliche Objekte mit demselben Inhalt zu erstellen. Aber es kann trotzdem passieren.
ThiefMaster
@ThiefMaster neigt die Antwort dazu, falsch interpretiert zu werden? Beim erneuten Lesen konnte ich es jedoch nicht finden (mit der Erwähnung von "einigen Ausnahmen"). Ihre Aussage gilt nur für Zeichenfolgen und nicht int, oder?
Blutende Finger
Nicht wirklich, aber da Sie dieses Beispiel in Ihrer Antwort haben, dachte ich, es wäre eine gute Idee, Benutzer zu warnen, dass es eine schlechte Idee ist, das tatsächlich zu verwenden. Vielleicht fügen Sie etwas wie "# cpython spezifisch / nicht garantiert" hinter dieser Zeile hinzu ...
ThiefMaster
1

John Machins Schlussfolgerung, dass Nonees sich um einen Singleton handelt, wird durch diesen Code gestützt.

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

Da Noneist ein Singleton x == Noneund x is Nonehätte das gleiche Ergebnis. Meiner ästhetischen Meinung nach x == Noneist es jedoch am besten.

ncmathsadist
quelle
2
Ich bin mit der Meinung am Ende dieser Antwort nicht einverstanden. Beim expliziten Vergleich mit none wird normalerweise beabsichtigt, dass das betreffende NoneObjekt genau das Objekt ist. Im Vergleich dazu sieht man selten, dass None in einem anderen Kontext verwendet wird, außer dass es ähnlich Falseist, wenn andere Werte wahr sind. In diesen Fällen ist es idiomatischer, so etwas wieif 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
Aks
quelle