Python: Unterschied zwischen == und is Operatoren

Prämisse: Variablen sind Pointer auf Objekte im Speicher.

  • == vergleicht die Werte von zwei Variablen und schaut nicht, ob es sich um das selbe Objekt im Speicher handelt.
  • is hingegen vergleicht bzw. prüft, ob es sich um das selbe Objekt im Speicher handelt.

Folgender Python-Code veranschaulicht den Unterschied:

a = [1, 2, 3]
b = [1, 2, 3]

print(id(a), id(b))

print(a == b)
print(a is b)

und erzeugt folgende Ausgabe:

2691913515776 2691915438912
True
False

Der Unterschied zwischen Operatoren sollte unbedingt bekannt sein, da dieser unter Umständen zu ungewolltem Verhalten führen kann.

Ausnahmen und Sonderfälle

Gleichsetzen von Variablen

Wenn Variablen gleich gesetzt werden, dann zeigen sie auf das gleiche Objekt im Speicher.

Folgender Python-Code veranschaulicht dies:

a = [1, 2, 3]
b = [1, 2, 3]

a = b

print(id(a), id(b))

print(a == b)
print(a is b)

und erzeugt folgende Ausgabe:

140497929272704 140497929272704
True
True

Überschreiben von __eq__ bei selbst geschriebenen Klassen

Bei dem Operator == wird die dunder-method __eq__ verwendet, welche rein theoretisch überschrieben werden kann. Dies bedeutet, dass man nicht immer davon ausgehen sollte, dass == so funktioniert, wie man es erwartet. is hingegen funktioniert immer auf die gleiche Art und Weise und vergleicht die Objekte, auf die im Speicher gezeigt wird.

Der folgende Code sollte das veranschaulichen:

class TestKlasse:
    def __init__(self, wert) -> None:
        self.testVar = wert

    def __eq__(self, other) -> bool:
        return False


c = TestKlasse(wert="Hallo")
d: TestKlasse = c


print(id(c), id(d))

print(c == d)
print(c is d)

durch folgende Ausgabe:

140356530760144 140356530760144
False
True

Es wird also auf dasselbe Objekt gezeigt (siehe id), aber weil die __eq__Methode überschrieben wurde, funktioniert == nicht mehr, wie man es erwarten würde.

Interning des Python Interpreters

“In computer science, interning is re-using objects of equal value on-demand instead of creating new objects”

Wikipedia: https://en.wikipedia.org/wiki/Interning_(computer_science)

Je nach Plattform und Python-Interpreter kann es sein, dass sich der Interpreter dazu entscheidet, den Pointer von zwei Variablen auf die selbe Speicherstelle verweisen zu lassen, sofern der Wert gleich ist.

Der folgende Code konstruiert diese Situation:

e = "Hallo"
f = "Hallo"

print(id(e), id(f))

print(e == f)
print(e is f)

und zeigt es mit der Ausgabe:

140639697683504 140639697683504
True
True

Obwohl zwei unterschiedliche Variablen (e und f) definiert werden, wird auf dieselbe Speicherstelle verwiesen, wodurch der is Operator anders funktioniert, als man intuitiv meinen möchte. Interning ist ein sogenanntes Implementierungsdetail und keine Regel. Das Verhalten kann also immer wieder anders sein.

Wann sollte man welchen der beiden Operatoren verwenden?

Anhand der Bespiele lässt sich ableiten, dass man den == Operator dann nutzen sollte, wenn man z.B. zwei Strings vergleichen möchte und/oder wenn man sich sicher sein kann, dass die __eq__ Methode nicht überschrieben wurde.

Den is Operator sollte man eigentlich nur bei Vergleichen mit singleton objects, wie z.B. None, True oder False, verwenden, da es immer nur ein Objekt dieser singleton objects im Speicher geben kann. Dies wird auch in PEP8 explizit so definiert.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert