628 Stimmen

Gibt es einen Unterschied zwischen "==" und "ist"?

Meine Google-fu hat mich im Stich gelassen.

Sind die beiden folgenden Gleichheitstests in Python gleichwertig?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

Gilt dies auch für Objekte, bei denen Sie Instanzen vergleichen würden (eine list sagen)?

Okay, das beantwortet meine Frage:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

Also == Testwert, bei dem is Tests, um festzustellen, ob es sich um dasselbe Objekt handelt?

1168voto

Torsten Marek Punkte 78610

is wird zurückgegeben True wenn zwei Variablen auf das gleiche Objekt (im Speicher) zeigen, == wenn die Objekte, auf die sich die Variablen beziehen, gleich sind.

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

In Ihrem Fall funktioniert der zweite Test nur, weil Python kleine Integer-Objekte zwischenspeichert, was ein Implementierungsdetail ist. Bei größeren Ganzzahlen funktioniert dies nicht:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

Das Gleiche gilt für String-Literale:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Siehe bitte diese Frage auch.

408voto

John Feminella Punkte 292907

Es gibt eine einfache Faustregel, die Ihnen sagt, wann Sie Folgendes verwenden sollten == ou is .

  • == ist für Wertgleichheit . Verwenden Sie es, wenn Sie wissen möchten, ob zwei Objekte den gleichen Wert haben.
  • is ist für Referenzgleichheit . Verwenden Sie es, wenn Sie wissen möchten, ob sich zwei Referenzen auf dasselbe Objekt beziehen.

Wenn man etwas mit einem einfachen Typ vergleicht, prüft man in der Regel auf Wertgleichheit verwenden, also sollten Sie == . In Ihrem Beispiel geht es wahrscheinlich darum, zu prüfen, ob x den Wert 2 hat ( == ), nicht ob x bezieht sich buchstäblich auf dasselbe Objekt wie 2.


Ein weiterer Hinweis: Aufgrund der Art und Weise, wie die CPython-Referenzimplementierung funktioniert, erhalten Sie unerwartete und inkonsistente Ergebnisse, wenn Sie fälschlicherweise die is für die Referenzgleichheit bei ganzen Zahlen zu vergleichen:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

Das ist so ziemlich das, was wir erwartet haben: a y b haben den gleichen Wert, sind aber unterschiedliche Einheiten. Aber was ist damit?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

Dies steht im Widerspruch zu dem früheren Ergebnis. Was ist hier los? Es stellt sich heraus, dass die Referenzimplementierung von Python Ganzzahlobjekte im Bereich -5 256 aus Leistungsgründen als Singleton-Instanzen zwischenspeichert. Hier ist ein Beispiel, das dies demonstriert:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

Dies ist ein weiterer offensichtlicher Grund gegen die Verwendung von is : Das Verhalten wird den Implementierungen überlassen, wenn man es fälschlicherweise für die Wertgleichheit verwendet.

62voto

Gibt es einen Unterschied zwischen == y is in Python?

Ja, sie haben einen sehr wichtigen Unterschied.

== : Prüfung auf Gleichheit - die Semantik besagt, dass äquivalente Objekte (die nicht unbedingt dasselbe Objekt sind) als gleich getestet werden. Da die Dokumentation sagt :

Die Operatoren <, >, ==, >=, <= und != vergleichen die Werte von zwei Objekten.

is Identitätsprüfung - die Semantik ist, dass das Objekt (wie im Speicher gehalten) ist das Objekt. Auch hier gilt, dass die Dokumentation sagt :

Die Betreiber is y is not Test auf Objektidentität: x is y ist wahr wenn und nur wenn x y y sind das gleiche Objekt. Die Objektidentität wird mit Hilfe der id() Funktion. x is not y ergibt den Kehrwert Wahrheitswert.

Die Identitätsprüfung ist also dasselbe wie die Prüfung der Gleichheit der IDs der Objekte. Das heißt,

a is b

ist dasselbe wie:

id(a) == id(b)

wobei id ist die eingebaute Funktion, die eine Ganzzahl zurückgibt, die "unter gleichzeitig existierenden Objekten garantiert eindeutig ist" (siehe help(id) ) und wo a y b sind beliebige Objekte.

Andere Verwendungszwecke

Sie sollten diese Vergleiche aufgrund ihrer Semantik verwenden. Verwenden Sie is zur Überprüfung der Identität und == um die Gleichheit zu prüfen.

Im Allgemeinen verwenden wir also is um die Identität zu überprüfen. Dies ist in der Regel nützlich, wenn wir nach einem Objekt suchen, das nur einmal im Speicher vorhanden sein sollte, was in der Dokumentation als "Singleton" bezeichnet wird.

Anwendungsfälle für is umfassen:

  • None
  • Enum-Werte (bei Verwendung von Enums aus dem Enum-Modul)
  • in der Regel Module
  • normalerweise Klassenobjekte, die sich aus Klassendefinitionen ergeben
  • normalerweise Funktionsobjekte, die sich aus Funktionsdefinitionen ergeben
  • alles andere, das nur einmal im Speicher vorhanden sein sollte (im Allgemeinen alle Singletons)
  • ein bestimmtes Objekt, das Sie nach Identität suchen

Übliche Anwendungsfälle für == umfassen:

  • Zahlen, einschließlich ganzer Zahlen
  • Zeichenketten
  • Listen
  • setzt
  • Wörterbücher
  • benutzerdefinierte veränderbare Objekte
  • andere eingebaute unveränderliche Objekte, in den meisten Fällen

Der allgemeine Anwendungsfall, wiederum für == ist, dass das gewünschte Objekt möglicherweise nicht das dieselbe Objekt, stattdessen kann es sich um ein gleichwertig eine

PEP 8 Richtungen

PEP 8, der offizielle Python-Style-Guide für die Standardbibliothek, erwähnt ebenfalls zwei Anwendungsfälle für is :

Vergleiche mit Singletons wie None sollte immer mit is oder is not , niemals die Gleichheitsoperatoren.

Hüten Sie sich auch davor, zu schreiben if x wenn Sie wirklich meinen if x is not None -- z.B. beim Testen, ob eine Variable oder ein Argument, das standardmäßig auf None auf einen anderen Wert gesetzt wurde. Der andere Wert könnte einen Typ haben (wie wie ein Container), der in einem booleschen Kontext falsch sein könnte!

Von der Identität auf die Gleichheit schließen

Wenn is wahr ist, kann Gleichheit in der Regel abgeleitet werden - wenn ein Objekt sich selbst ist, dann sollte es logischerweise als gleichwertig mit sich selbst getestet werden.

In den meisten Fällen ist diese Logik richtig, aber sie hängt von der Implementierung der __eq__ besondere Methode. Da die docs sagen,

Das Standardverhalten für den Gleichheitsvergleich ( == y != ) basiert auf der Identität der Objekte. Daher führt der Gleichheitsvergleich von Instanzen mit der gleichen Identität ergibt Gleichheit, und der Gleichheitsvergleich von Instanzen mit unterschiedlichen Identitäten führt zu Ungleichheit. A Motivation für dieses Standardverhalten ist der Wunsch, dass alle Objekte reflexiv sein sollten (d.h. x ist y impliziert x == y).

und empfiehlt im Interesse der Kohärenz:

Der Gleichheitsvergleich sollte reflexiv sein. Mit anderen Worten, identische Objekte sollten gleich verglichen werden:

x is y impliziert x == y

Wir sehen, dass dies das Standardverhalten für benutzerdefinierte Objekte ist:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

Der umgekehrte Fall trifft in der Regel auch zu: Wenn etwas nicht gleich ist, kann man daraus schließen, dass es sich nicht um dasselbe Objekt handelt.

Da Gleichheitstests angepasst werden können, gilt diese Schlussfolgerung nicht immer für alle Typen.

Eine Ausnahme

Eine bemerkenswerte Ausnahme ist nan - Es wird immer als ungleich sich selbst getestet:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False

Die Prüfung auf Identität kann viel schneller sein als die Prüfung auf Gleichheit (die eine rekursive Prüfung der Mitglieder erfordern könnte).

Sie kann jedoch nicht als Ersatz für die Gleichheit dienen, wenn mehr als ein Objekt als gleichwertig angesehen wird.

Beachten Sie, dass beim Vergleich der Gleichheit von Listen und Tupeln davon ausgegangen wird, dass die Identität der Objekte gleich ist (da dies eine schnelle Prüfung ist). Dies kann zu Widersprüchen führen, wenn die Logik inkonsistent ist - wie es bei nan :

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

Ein abschreckendes Beispiel:

Die Frage ist der Versuch, die is um ganze Zahlen zu vergleichen. Sie sollten nicht davon ausgehen, dass eine Instanz einer Ganzzahl dieselbe Instanz ist wie eine, die durch einen anderen Verweis erhalten wurde. Diese Geschichte erklärt, warum.

Ein Kommentator hatte Code, der sich auf die Tatsache verließ, dass kleine ganze Zahlen (-5 bis 256 einschließlich) in Python Singletons sind, anstatt auf Gleichheit zu prüfen.

Wow, das kann zu einigen heimtückischen Fehlern führen. Ich hatte einen Code, der überprüfte, ob a gleich b ist, was wie gewünscht funktionierte, weil a und b typischerweise kleine Zahlen sind. Der Fehler trat erst heute auf, nach sechs Monaten in der Produktion, weil a und b schließlich groß genug waren, um nicht zwischengespeichert zu werden. - gwg

In der Entwicklung hat es funktioniert. Möglicherweise hat es einige Untests bestanden.

Und es funktionierte in der Produktion - bis der Code nach einer Ganzzahl größer als 256 suchte, woraufhin er in der Produktion fehlschlug.

Dies ist ein Produktionsfehler, der bei der Codeüberprüfung oder möglicherweise mit einem Style-Checker hätte entdeckt werden können.

Ich möchte betonen: nicht verwenden is um ganze Zahlen zu vergleichen.

48voto

stephenbayer Punkte 12054

== bestimmt, ob die Werte gleich sind, während is bestimmt, ob es sich um genau dasselbe Objekt handelt.

26voto

MSeifert Punkte 131411

Was ist der Unterschied zwischen is y == ?

== y is sind unterschiedliche Vergleiche! Wie andere schon sagten:

  • == vergleicht die Werte der Objekte.
  • is vergleicht die Referenzen der Objekte.

In Python beziehen sich Namen auf Objekte, zum Beispiel in diesem Fall value1 y value2 beziehen sich auf eine int Instanz, die den Wert 1000 :

value1 = 1000
value2 = value1

enter image description here

Denn value2 bezieht sich auf das gleiche Objekt is y == wird geben True :

>>> value1 == value2
True
>>> value1 is value2
True

Im folgenden Beispiel werden die Namen value1 y value2 beziehen sich auf verschiedene int Instanzen, auch wenn beide die gleiche ganze Zahl speichern:

>>> value1 = 1000
>>> value2 = 1000

enter image description here

Weil derselbe Wert (Ganzzahl) gespeichert wird == wird sein True Deshalb wird er auch oft als "Wertvergleich" bezeichnet. Allerdings is wird zurückgegeben False weil es sich um unterschiedliche Objekte handelt:

>>> value1 == value2
True
>>> value1 is value2
False

Wann ist was zu verwenden?

Im Allgemeinen is ist ein viel schnellerer Vergleich. Das ist der Grund, warum CPython Caches (oder vielleicht wiederverwendet wäre der bessere Ausdruck) bestimmte Objekte wie kleine Ganzzahlen, einige Zeichenketten usw. Dies sollte jedoch behandelt werden als Umsetzungsdetails die sich (auch wenn es unwahrscheinlich ist) jederzeit ohne Vorwarnung ändern können.

Sie sollten nur verwenden is wenn Sie:

  • prüfen wollen, ob zwei Objekte wirklich dasselbe Objekt sind (nicht nur derselbe "Wert"). Ein Beispiel wäre, wenn Sie ein Singleton-Objekt als Konstante verwenden.

  • einen Wert mit einem Wert vergleichen wollen Python Konstante . Die Konstanten in Python sind:

    • None
    • True 1
    • False 1
    • NotImplemented
    • Ellipsis
    • __debug__
    • Klassen (zum Beispiel int is int ou int is float )
    • es könnten zusätzliche Konstanten in eingebauten Modulen oder Modulen von Drittanbietern vorhanden sein. Zum Beispiel np.ma.masked aus dem NumPy-Modul)

In allen anderen Fällen sollten Sie == um die Gleichheit zu prüfen.

Kann ich das Verhalten anpassen?

Es gibt einen Aspekt, der == das nicht schon in den anderen Antworten erwähnt wurde: Es ist Teil der Pythons "Datenmodell" . Das bedeutet, dass sein Verhalten mit der Option __eq__ Methode. Zum Beispiel:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

Dies ist nur ein künstliches Beispiel, um zu verdeutlichen, dass die Methode wirklich aufgerufen wird:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

Beachten Sie, dass standardmäßig (wenn keine andere Implementierung von __eq__ in der Klasse oder den Oberklassen zu finden sind) __eq__ verwendet is :

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

Es ist also wichtig, die __eq__ wenn Sie "mehr" als nur einen Referenzvergleich für benutzerdefinierte Klassen wünschen!

Auf der anderen Seite können Sie keine Anpassungen vornehmen is Kontrollen. Sie vergleicht immer nur wenn Sie die gleiche Referenz haben.

Werden diese Vergleiche immer einen booleschen Wert ergeben?

Denn __eq__ kann neu implementiert oder überschrieben werden und ist nicht auf die Rückgabe von True ou False . Sie könnte irgendetwas zurückgeben (aber in den meisten Fällen sollte es einen booleschen Wert zurückgeben!).

Zum Beispiel mit NumPy-Arrays die == wird ein Array zurückgeben:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

Aber is Prüfungen ergeben immer True ou False !


1 Wie Aaron Hall in den Kommentaren erwähnte:

Im Allgemeinen sollten Sie keine is True ou is False Prüfungen, weil man diese "Prüfungen" normalerweise in einem Kontext verwendet, der implizit die Zustand in einen Booleschen Wert umwandeln (zum Beispiel in einer if Anweisung). Wenn Sie also die is True Vergleich et der implizite boolesche Cast macht mehr Arbeit als nur der boolesche Cast - und man beschränkt sich auf Boolesche (was nicht als pythonisch gilt).

Wie PEP8 bereits erwähnt hat:

Vergleichen Sie keine booleschen Werte mit True ou False mit == .

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X