Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
1 Einleitung
2 Die Programmiersprache Python
Teil I Einstieg in Python
3 Erste Schritte im interaktiven Modus
4 Der Weg zum ersten Programm
5 Kontrollstrukturen
6 Dateien
7 Das Laufzeitmodell
8 Funktionen, Methoden und Attribute
9 Informationsquellen zu Python
Teil II Datentypen
10 Das Nichts – NoneType
11 Operatoren
12 Numerische Datentypen
13 Sequenzielle Datentypen
14 Zuordnungen
15 Mengen
16 Collections
17 Datum und Zeit
18 Aufzählungstypen – Enum
Teil III Fortgeschrittene Programmiertechniken
19 Funktionen
20 Modularisierung
21 Objektorientierung
22 Ausnahmebehandlung
23 Iteratoren
24 Kontextobjekte
25 Manipulation von Funktionen und Methoden
Teil IV Die Standardbibliothek
26 Mathematik
27 Kryptografie
28 Reguläre Ausdrücke
29 Schnittstelle zu Betriebssystem und Laufzeitumgebung
30 Kommandozeilenparameter
31 Dateisystem
32 Parallele Programmierung
33 Datenspeicherung
34 Netzwerkkommunikation
35 Debugging und Qualitätssicherung
36 Dokumentation
Teil V Weiterführende Themen
37 Anbindung an andere Programmiersprachen
38 Distribution von Python-Projekten
39 Grafische Benutzeroberflächen
40 Python als serverseitige Programmiersprache im WWW – ein Einstieg in Django
41 Wissenschaftliches Rechnen
42 Insiderwissen
43 Von Python 2 nach Python 3
A Anhang
Stichwortverzeichnis

Download:
- Beispielprogramme, ca. 464 KB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Python 3 von Johannes Ernesti, Peter Kaiser
Das umfassende Handbuch
Buch: Python 3

Python 3
Pfeil 7 Das Laufzeitmodell
Pfeil 7.1 Die Struktur von Instanzen
Pfeil 7.1.1 Datentyp
Pfeil 7.1.2 Wert
Pfeil 7.1.3 Identität
Pfeil 7.2 Referenzen und Instanzen freigeben
Pfeil 7.3 Mutable vs. immutable Datentypen
Pfeil 7.3.1 Mutable Datentypen und Seiteneffekte
 
Zum Seitenanfang

7.3    Mutable vs. immutable Datentypen Zur vorigen ÜberschriftZur nächsten Überschrift

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.

 
Zum Seitenanfang

7.3.1    Mutable Datentypen und Seiteneffekte Zur vorigen ÜberschriftZur nächsten Überschrift

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.

Der Operator += mit str-Instanzen

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.

Der Operator += für list-Instanzen

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.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Python 3 Python 3
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Einstieg in Python
Einstieg in Python


Zum Rheinwerk-Shop: Python. Der Grundkurs
Python. Der Grundkurs


Zum Rheinwerk-Shop: Algorithmen mit Python
Algorithmen mit Python


Zum Rheinwerk-Shop: Objektorientierte Programmierung
Objektorientierte Programmierung


Zum Rheinwerk-Shop: Raspberry Pi. Das umfassende Handbuch
Raspberry Pi. Das umfassende Handbuch


Zum Rheinwerk-Shop: Roboter-Autos mit dem Raspberry Pi
Roboter-Autos mit dem Raspberry Pi


Zum Rheinwerk-Shop: Neuronale Netze programmieren mit Python
Neuronale Netze programmieren mit Python


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2020
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern