In einem Kommentar zu dieser Frage sah ich eine Aussage, die die Verwendung empfahl
result is not None
vs.
result != None
Ich habe mich gefragt, was der Unterschied ist und warum einer dem anderen empfohlen werden könnte.
In einem Kommentar zu dieser Frage sah ich eine Aussage, die die Verwendung empfahl
result is not None
vs.
result != None
Ich habe mich gefragt, was der Unterschied ist und warum einer dem anderen empfohlen werden könnte.
Antworten:
==
ist ein Gleichheitstest . Es wird geprüft, ob die rechte und die linke Seite gleiche Objekte sind (entsprechend ihrer __eq__
oder ihrer __cmp__
Methoden).
is
ist ein Identitätstest . Es wird geprüft, ob die rechte und die linke Seite dasselbe Objekt sind. Es werden keine Methodenaufrufe durchgeführt, Objekte können den is
Vorgang nicht beeinflussen .
Sie verwenden is
(und is not
) für Singletons, z. B. None
wenn Sie sich nicht für Objekte interessieren, die dies vorgeben möchten, None
oder wenn Sie sich vor Objekten schützen möchten, die beim Vergleich mit Objekten brechen None
.
None
hat wenige Methoden und fast keine Attribute. Wenn Ihr __eq__
Test eine Methode oder ein Attribut erwartet hat, ist diese möglicherweise fehlerhaft. def __eq__( self, other ): return self.size == other.size
. Zum Beispiel wird brechen, wenn other
zufällig ist None
.
is
ist wie Javas ==
. Pythons ==
ist wie Javas .equals()
. Dies hilft natürlich nur, wenn Sie Java kennen.
is
wie ===
(sehr gleich) und umgekehrt is not
wie !==
(nicht genau gleich) ist.
is not
ein einzelner Operator oder negiert er nur das Ergebnis von is
intern wie not foo is bar
?
Lassen Sie mich zunächst einige Begriffe durchgehen. Wenn Sie nur Ihre Frage beantworten möchten, scrollen Sie nach unten zu "Beantworten Ihrer Frage".
Objektidentität : Wenn Sie ein Objekt erstellen, können Sie es zu einer Variablen zuweisen können. Sie können es dann auch einer anderen Variablen zuweisen. Und ein anderer.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
In diesem Fall cancel
, close
und dismiss
beziehen sich alle auf das gleiche Objekt im Speicher. Sie haben nur ein Button
Objekt erstellt, und alle drei Variablen beziehen sich auf dieses eine Objekt. Wir sagen das cancel
, close
und dismiss
alle beziehen sich auf identische Objekte; Das heißt, sie beziehen sich auf ein einzelnes Objekt.
Objektgleichheit : Wenn Sie zwei Objekte vergleichen, ist es Ihnen normalerweise egal, dass sie sich auf genau dasselbe Objekt im Speicher beziehen . Mit der Objektgleichheit können Sie Ihre eigenen Regeln für den Vergleich zweier Objekte definieren. Wenn Sie schreiben if a == b:
, sagen Sie im Wesentlichen if a.__eq__(b):
. Auf diese Weise können Sie eine __eq__
Methode definieren a
, mit der Sie Ihre eigene Vergleichslogik verwenden können.
Begründung: Zwei Objekte haben genau die gleichen Daten, sind jedoch nicht identisch. (Sie sind nicht dasselbe Objekt im Speicher.) Beispiel: Strings
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Hinweis: Ich verwende hier Unicode-Zeichenfolgen, da Python intelligent genug ist, um reguläre Zeichenfolgen wiederzuverwenden, ohne neue im Speicher zu erstellen.
Hier habe ich zwei Unicode-Strings a
und b
. Sie haben genau den gleichen Inhalt, aber sie sind nicht das gleiche Objekt im Speicher. Wenn wir sie jedoch vergleichen, möchten wir, dass sie gleich sind. Was hier passiert ist, dass das Unicode-Objekt die __eq__
Methode implementiert hat .
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Hinweis: __eq__
on unicode
ist definitiv effizienter implementiert.
Begründung: Zwei Objekte haben unterschiedliche Daten, werden jedoch als dasselbe Objekt betrachtet, wenn einige Schlüsseldaten identisch sind. Beispiel: Die meisten Arten von Modelldaten
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Hier habe ich zwei Dell-Monitore a
und b
. Sie haben die gleiche Marke und das gleiche Modell. Sie haben jedoch weder dieselben Daten noch dasselbe Objekt im Speicher. Wenn wir sie jedoch vergleichen, möchten wir, dass sie gleich sind. Was hier passiert, ist, dass das Monitor-Objekt die __eq__
Methode implementiert hat .
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
None
Verwenden Sie im Vergleich zu immer is not
. Keiner ist ein Singleton in Python - es gibt immer nur eine Instanz davon im Speicher.
Durch den Vergleich der Identität kann dies sehr schnell durchgeführt werden. Python prüft, ob das Objekt, auf das Sie sich beziehen, dieselbe Speicheradresse wie das globale None-Objekt hat - ein sehr, sehr schneller Vergleich zweier Zahlen.
Durch den Vergleich der Gleichheit muss Python nachschlagen, ob Ihr Objekt über eine __eq__
Methode verfügt. Ist dies nicht der Fall, wird jede Oberklasse auf der Suche nach einer __eq__
Methode untersucht. Wenn es eines findet, ruft Python es auf. Dies ist besonders schlimm, wenn die __eq__
Methode langsam ist und nicht sofort zurückkehrt, wenn sie bemerkt, dass das andere Objekt ist None
.
Haben Sie nicht implementiert __eq__
? Dann wird Python wahrscheinlich die __eq__
Methode finden object
und diese stattdessen verwenden - die ohnehin nur die Objektidentität überprüft.
Wenn Sie die meisten anderen Dinge in Python vergleichen, werden Sie verwenden !=
.
Folgendes berücksichtigen:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
None
ist ein Singleton, daher funktioniert der Identitätsvergleich immer, während ein Objekt den Gleichheitsvergleich über vortäuschen kann .__eq__()
.
None
, aber falsches Verhalten in Bezug auf None
könnte als Nebeneffekt der Implementierung von Gleichheit gegen andere Typen auftreten. Es sind weniger Auswirkungen auf die Sicherheit als vielmehr Auswirkungen auf die Korrektheit.
>>> () ist () Wahr >>> 1 ist 1 Wahr >>> (1,) == (1,) Wahr >>> (1,) ist (1,) Falsch >>> a = (1,) >>> b = a >>> a ist b Wahr
Einige Objekte sind Singletons und entsprechen daher is
mit ihnen ==
. Die meisten sind es nicht.
()
und 1
sind nicht von Natur aus Singletons.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) und leere Tupel sind Singletons. Es ist zwar weder dokumentiert noch garantiert, aber es ist unwahrscheinlich, dass es sich ändert.