7.3 Mutable vs. immutable Datentypen 

Vielleicht sind Sie beim Ausprobieren des gerade Beschriebenen schon auf den folgenden scheinbaren Widerspruch gestoßen:
>>> a = 1
>>> b = 1
>>> id(a)
9656320
>>> id(b)
9656320
>>> a is b
True
Warum referenzieren a und b dieselbe Ganzzahl-Instanz, wie es der Identitätenvergleich zeigt, obwohl wir in den ersten beiden Zeilen ausdrücklich zwei Instanzen mit dem Wert 1 erzeugt haben?
Um diese Frage zu beantworten, müssen Sie wissen, dass Python grundlegend zwischen zwei Arten von Datentypen unterscheidet: zwischen mutablen (dt. »veränderlichen«) Datentypen und immutablen (dt. »unveränderlichen«) Datentypen. Wie die Namen schon sagen, besteht der Unterschied zwischen den beiden Arten darin, ob sich der Wert einer Instanz zur Laufzeit ändern kann, ob sie also veränderbar ist. Instanzen eines mutablen Typs sind dazu in der Lage, nach ihrer Erzeugung andere Werte anzunehmen, während dies bei immutablen Datentypen nicht der Fall ist.
Wenn sich der Wert einer Instanz aber nicht ändern kann, ergibt es auch keinen Sinn, mehrere immutable Instanzen des gleichen Wertes im Speicher zu verwalten, weil im Optimalfall genau eine Instanz ausreicht, auf die dann alle entsprechenden Referenzen verweisen. Wie Sie sich nun sicherlich denken, handelt es sich bei Ganzzahlen um solch einen immutablen Datentyp, und Python hat aus Optimierungsgründen bei beiden Einsen auf dieselbe Instanz verweisen lassen. Auch Strings sind immutabel.[ 24 ](Das bedeutet natürlich nicht, dass Strings und Ganzzahlen aus Sicht des Programmierers unveränderlich sind. Es wird nur bei jeder Manipulation eines immutablen Datentyps eine neue Instanz des Datentyps erzeugt, anstatt die alte zu verändern. )
Es ist allerdings nicht garantiert, dass es immer nur genau eine Instanz zu jedem benötigten Wert eines unveränderlichen Datentyps gibt, obwohl dies theoretisch möglich wäre. Jede Implementierung von Python kann hier ihre eigene Variante wählen.
7.3.1 Mutable Datentypen und Seiteneffekte 

Bei den mutablen, also den veränderlichen Datentypen sieht es anders aus: Weil Python damit rechnen muss, dass sich der Wert einer solchen Instanz nachträglich ändern wird, ist das oben erläuterte System, nach Möglichkeit bereits vorhandene Instanzen erneut zu referenzieren, nicht sinnvoll. Hier kann man sich also darauf verlassen, dass immer eine neue Instanz erzeugt wird.
Dieses unterschiedliche Verhalten beim Umgang mit mutablen und immutablen Datentypen führt dazu, dass der gleiche Code für verschiedene Datentypen fundamental anderes bewirken kann. Die folgenden Beispiele dienen dazu, Sie für die damit verbundenen Besonderheiten zu sensibilisieren.
Zunächst führen wir den Operator += ein, mit dem an einen bereits vorhandenen String ein weiterer angehängt werden kann:
>>> a = "Wasser"
>>> a += "flasche"
>>> a
'Wasserflasche'
Hier wird also zunächst ein String mit dem Wert "Wasser" erzeugt, an den dann der String "flasche" angehängt wird.
Genauso ist es möglich, mithilfe von += an eine bestehende Liste die Elemente einer weiteren Liste anzuhängen:
>>> a = [1,2]
>>> a += [3,4]
>>> a
[1, 2, 3, 4]
Es deutet also alles darauf hin, dass der Operator += für Strings und Listen das Gleiche leistet. Tatsächlich besteht aber ein gravierender Unterschied.
Im nächsten Beispiel werden wir zweimal den gleichen Code ausführen, einmal für einen String und einmal für eine Liste.
>>> a = "Wasser"
>>> b = a
>>> a += "flasche"
>>> a
'Wasserflasche'
>>> b
'Wasser'
Wieder wird ein String mit dem Wert "Wasser" erzeugt. Dieses Mal lassen wir neben der Referenz a zusätzlich noch die Referenz b auf diesen String zeigen. Dann hängen wir an den von a referenzierten String erneut den String "flasche" an und sehen bei der Ausgabe, dass b immer noch den String "Wasser" referenziert, während a auf die Verkettung "Wasserflasche" zeigt.
Führen wir das Gleiche mit Instanzen des Typs list aus, ergibt sich ein anderes Bild:
>>> a = [1,2]
>>> b = a
>>> a += [3,4]
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
Dieses Beispiel ist analog zum vorangegangenen Beispiel mit den String-Instanzen: Die Liste [1,2] entspricht dem String "Wasser" und die Liste [3,4] dem String "flasche". Trotzdem hat sich die von b referenzierte Liste in diesem Beispiel verändert, was bei dem String-Beispiel nicht der Fall war.
Um diesen Unterschied zu verstehen, betrachten wir die Vorgänge der beiden Code-Sequenzen im Detail.
In Abbildung 7.8 sind der Beispiel-Code für Strings und die daraus resultierenden internen Vorgänge gegenübergestellt.
Abbildung 7.8 Der Operator += mit str-Instanzen
Der Knackpunkt befindet sich in der Zeile a += "flasche". Da str ein immutabler Datentyp ist, ist es nicht möglich, die bestehende str-Instanz "Wasser" durch Anhängen von "flasche" zu erweitern. Stattdessen wird an dieser Stelle eine neue str-Instanz mit dem Wert "Wasserflasche" erzeugt und anschließend von a referenziert. Die weiterhin von b referenzierte Instanz mit dem Wert "Wasser" ist davon nicht betroffen.
Anders verhält es sich beim Listenbeispiel, wie Abbildung 7.9 zeigt.
Abbildung 7.9 Der Operator += für list-Instanzen
Da list ein mutabler Datentyp ist, kann die gemeinsam von a und b referenzierte list-Instanz verändert werden. Die Zeile a += [3,4] bewirkt daher nicht, dass eine neue list-Instanz erzeugt wird, sondern verändert die bereits bestehende Instanz. Dies hat zur Folge, dass a und b weiterhin dieselbe Liste referenzieren und somit auch b von der Manipulation an a betroffen ist.
Man nennt diesen Vorgang, bei dem etwas über Vorgänge an einer anderen Stelle beeinflusst wird, einen Seiteneffekt.
Seiteneffekte treten aus prinzipiellen Gründen ausschließlich bei mutablen Datentypen auf und sind nicht auf den +=-Operator beschränkt. Sie kommen immer dann ins Spiel, wenn die Instanz eines mutablen Datentyps verändert wird.
Während der weiteren Lektüre dieses Buchs werden Sie eine ganze Reihe mutabler Datentypen und Operationen, mit denen sie verändert werden können, kennenlernen. Dabei sollten Sie das hier vorgestellte Verhalten im Hinterkopf behalten.