Unterschied zwischen == und is Operatoren in Python
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:
PS C:\Users\frede\Desktop> py.exe .\test.py
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, wenn man eigene Klassen schreibt. 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, wenn 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)
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
, da es immer nur ein Objekt dieser singleton object im Speicher geben kann. Dies wird auch in PEP8 explizit so definiert.