Exkurs: (un-)veränderbare Objekte#

In Python gibt es veränderbare und unveränderbare Objekte. Die eine Art von Objekten kann man also verändern, die andere Art von Objekten kann man nicht verändern.

Stell dir vor, du besitzt ein Auto. Um damit ordentlich Eindruck auf der Straße zu machen, möchtest du gerne dein Auto tunen lassen und von 100 PS auf 150 PS upgraden. Du fährst also in eine Werkstatt und bittest um die gewünschte Veränderung. In der Werkstatt könntest du nun zwei Dinge zu hören bekommen, nämlich entweder

  • “Ja, kein Problem, wir können dein Auto wie gewünscht verändern!”

oder

  • “Nein, deinen Autotyp kann man leider nicht wie gewünscht verändern. Wir können dir aber anbieten, dein Auto gegen ein anderes mit den gewünschten Eigenschaften einzutauschen!”.

Dein Auto ist also entweder ein veränderbares Objekt oder ein unveränderbares Objekt. Ist dein Auto veränderbar, so kann man es verändern, aber “dein Auto” ist nach der Veränderung immer noch “dein Auto” d.h. dasselbe (aber eben nun veränderte) Objekt. Ist dein Auto hingegen unveränderbar, du möchtest aber trotzdem die Veränderung, so bleibt dir nichts anderes übrig als “dein Auto” durch ein “anderes Auto” auszutauschen. Dadurch wird ein anderes Auto schließlich zu “deinem Auto”. Ein anderes Objekt nimmt dann also den Platz “deines Autos” ein.

Genau so ist das auch in Python. Es gibt Objekte, die kann man verändern, und Objekte, die kann man nicht verändern, sondern nur austauschen, wenn man etwas anderes will. Das ist relevant, wenn man Variablen bzw. die Objekte hinter den Variablen verändern möchten. In Python sind Variablen immer nur Beschriftungen für bzw. Zeiger auf Objekte, nicht aber die Objekte selbst. Das ist so, wie der Begriff “mein Auto” auf ein Auto verweist, aber nicht das Auto selbst ist, sondern nur ein Begriff bzw. Gedanke. Möchte man eine Variable in Python verändern, hängt es vom Objekt-Typ des von der Variable beschrifteten Objektes ab, ob

  • das Objekt verändert werden kann und die Variable nach der Veränderung immer noch auf dasselbe (aber eben nun veränderte) Objekt zeigt

oder

  • das Objekt nicht verändert werden kann, ausgetauscht werden muss und die Variable nach der Veränderung auf ein komplett anderes Objekt zeigt

Das ist so, wie im Beispiel oben, wo je nach Auto-Typ entweder das durch “mein Auto” beschriftete Auto verändert werden kann oder man tauscht das gesamte Auto aus, sodass die Beschriftung “mein Auto” einem neuen Objekt zugeordnet wird.

Schauen wir uns das mal konkret in Python an. Die meisten Standard-Objekte in Python sind unveränderbar. Dazu gehören z.B. Objekte vom Typ Integer, Float und String. Wenn wir z.B. das Integer-Objekt 100 einer Variable zuweisen, dann beschriften wir das Objekt 100 mit dem gewählten Variablennamen. Das mache ich beispielsweise hier:

my_integer = 100

Eine Variable ist aber, wie gesagt, wirklich immer nur eine Beschriftung eines Objektes und nicht das Objekt selbst. Daher verändere ich mit folgendem Code auch nicht das Objekt 100 in das Objekt 150, sondern beschrifte nun das Objekt 150 mit dem Namen my_integer:

my_integer = my_integer + 50
my_integer
150

Das Objekt 100 wurde also nicht verändert, sondern der Wert des Variablennamen my_variable überschrieben bzw. dem Variablenname my_variable wurde ein anderes Objekt zugewiesen.

Woher weiß ich, dass sich hinter der Variable my_integer nun ein vollkommen neues Objekt verbirgt und nicht dasselbe Objekt in veränderter Form? Das kann man u.a. mit der Funktion id() sehen. Steckt man ein Objekt in die Funktion id(), dann bekommt man eine Art Identifikationsnummer heraus über welche man ein Objekt eindeutig identifizieren kann. Gehen wir das obige Beispiel nochmal durch, aber wenden dabei immer wieder die Funktion id() an, um die wahre Identität der Objekte und Variablen zu enthüllen.

Hier weise ich zunächst die 100 der Variable my_integer zu:

my_integer = 100

Gucken wir mal, welche Identifikationsnummer uns die Funktion id() für die Variable my_integer bzw. für das Objekt, welches wir mit my_integer benannt haben, herausgibt:

id(my_integer)
140718436266880

Aha. Diese Zahl sagt uns alleine nicht wirklich viel. Interessanterweise ist aber diese Identifikationsnummer nichts anderes als die Identifikationsnummer des Objekts 100 selbst:

id(100)
140718436266880

Das ist logisch, wenn man bedenkt, dass die Variable my_integer nur eine Beschriftung für das eigentliche Objekt 100 ist. Die Variable my_integer verweist nur auf das Objekt 100.

Nun verändere ich die Variable my_integer, indem ich sie überschreibe:

my_integer = my_integer + 50

Welches Objekt versteckt sich jetzt hinter my_integer?

id(my_integer)
140718436268480

Jetzt hat sich die Identifikationsnummer verändert. Diese Identifikationsnummer ist nun die Identifikationsummer für das Objekt 150, auf welches die Variable my_integer nun verweist.

id(150)
140718436268480

Das ist alles etwas verwirrend. Denn eigentlich fühlt es sich ja so an, dass wir das “Objekt” my_integer verändern würden, wenn wir dieser Variable einen neuen Wert zuweisen. In Wahrheit ist die Variable my_integer ja aber nicht das Objekt selbst, sondern nur eine Beschriftung für ein Objekt. Wir ändern somit also die Zuordnung der Beschriftung. Wir tauschen das Objekt 100 gegen das Objekt 150 und beschriften nun eben die 150 mit my_integer. Das ist so, wie wenn wir bei “mein Auto” anfangen an ein neues Auto zu denken, falls das alte Auto ausgetauscht werden musste, weil es unveränderbar war.

Es gibt jedoch auch Objekte in Python, die können wir tatsächlich verändern. Bei diesen ist es dann so, dass wir wirklich das Objekt hinter dem Variablennamen verändern, sodass der Variablenname immer noch dasselbe, aber eben nun veränderte Objekt beschriftet (“mein Auto” bleibt “mein Auto”, wurde aber verändert). Zu den veränderbaren Objekten, die wir schon kennengelernt haben, gehören in Python z.B. die Listen!

Im Folgenden erstelle ich zunächst eine Liste und lasse mir dann die Identifikationsnummer der Liste ausgeben. Dann verändere ich die Liste und schaue, ob die Identität der Liste gleichgeblieben ist.

# Liste erstellen
my_list = [100, 200, 300]

# Identifikationsnummer ausgeben
id(my_list)
1875432623680
# Liste verändern
my_list.append(400)

# Liste nochmal verändern
my_list[0] = 0

# Liste angucken
my_list
[0, 200, 300, 400]
# Identifikationsnummer angucken
id(my_list)
1875432623680

Wir sehen, die Liste wurde verändert, ist aber nach wie vor dasselbe Objekt mit derselben Identifikationsnummer. Die Variable my_list verweist also nach wie vor auf dasselbe Objekt. Das Objekt selbst wurde aber verändert.

Uff! Das ist schon echt kompliziert. Nun wissen wir, dass es veränderbare und unveränderbare Objekte in Python gibt. Aber warum ist das wichtig? Ob ein Objekt veränderbar oder unveränderbar ist, macht eben immer dann einen Unterschied, wenn wir ein Objekt bzw. eine Variable verändern wollen. Und im Folgenden schauen wir uns an, wie man innerhalb von For-Loops die Elemente der Liste, auf die man im For-Loop zugreift, verändern kann. Je nachdem, ob die Elemente der Liste veränderbar sind oder nicht, müssen wir einen bestimmten Weg verwenden, um die Elemente in der Liste zu ändern.