Dateiname
EF-Informatik/exercises/referenzen.py
Jetzt, wo wir Listen in Python kennen, mĂĽssen wir unsere bisherige Vorstellung von Variablen ĂĽberdenken und anpassen.
Lesen Sie die untenstehende Einführung zum Thema Referenzen durch und führen Sie im Anschluss das Programm angehängte Programm referenzen.py im Debuuger von VS Code aus.
FĂĽhren Sie dann das Snippet refernzen.py im Debugger Ihres Visual Studio Code aus (falls Sie es noch nicht geklont haben, mĂĽssen Sie das zuerst tun).
Achten Sie auf die in der Konsole (unten) angezeigten Objekt-Ids und Datentypen. Daran können Sie erkennen, um welches Objekt es sich jeweils handelt und welchen Datentyp es hat.
Auf der linken Seite sehen Sie die aktuellen Objektwerte in den Variablen a und b. Achten Sie besonders, was dort passiert, wenn die Zeile 30 ausgefĂĽhrt wird.
EF-Informatik/exercises/referenzen.py
https://github.com/lebalz/ofi-blog/blob/main/docs/EF-Python/03-Python/10-referenzen/referenzen.py
Zum Schluss den Selbsttest ganz am Ende der Seite durchfĂĽhren...
Bisheriges Modell für Variablen​
Bisher haben wir uns Variablen als Karteikärtchen vorgestellt, auf welchen sich der Computer einen bestimmten Wert (eine Zahl, ein Text, etc.) merkt. Das Kärtchen trägt einen Namen. Unter diesem Namen kann die Information zu einem späteren Zeitpunkt wieder hervorgeholt werden. Die Zuweisung
a = 10
führt dazu, dass eine Kärtchen mit dem Namen a entsteht, auf welchem der Wert 10 notiert ist.
a |
---|
10 |
Wenn man der Variablen einen neuen Wert zuweist, so wird der notierte Wert ĂĽberschrieben und ersetzt.
a = "blah"
fĂĽhrt zu:
a |
---|
blah |
Mit der Einführung von Listen stösst dieses Modell an seine Grenzen und wir brauchen ein besseres Modell.
Etiketten statt Karteikärtchen - Referenzen und Objekte​
In diesem Modell werden die Karteikarten durch Etiketten ersetzt, welche mit einer Schnur an beliebige Gegenstände gebunden werden können.
Solche Gegenstände können alles sein, von einer einfachen Zahl, einem Text, bis zu einer langen Liste. Die Gegenstände entsprechen also den Dingen, welche wir uns merken wollen, weil wir sie später wieder brauchen. Man spricht jetzt nicht mehr von Werten, sondern von Objekten. Man kann sich Objekte auch als Behälter vorstellen, welche die eigentlichen Werte enthalten.
Damit man ein bestimmtes Objekt später wieder findet, wird es mit einer Etikette versehen, auf welcher ein Name steht. Unter diesem kann später das mit der Etikette verbundene Objekt wieder hervorgeholt werden.
Man kann sich dass auch wie ein Eimer vorstellen, in welchem sich die Objekte befinden, mit denen ein Programm arbeitet. Über den Rand des Eimers hängen Schnüre, an welchen Kärtchen befestigt sind. Auf jedem Kärtchen steht ein Name, welcher dazu dient, die verschiedenen Schnüre zu unterscheiden. Wenn man an einer Schnur zieht, so kommt das damit verbundene Objekt hervor. Man kann nun das Objekt verändern, oder dieses gar durch ein anderes Objekt ersetzen.
Eine Variable ist im neuen Modell also nichts anderes, als eine Etikette, welche mit einer Schnur an ein bestimmtes Objekt gebunden ist. Die Schnur wir als Referenz bezeichnet. Der Eimer aus obigem Vergleich entspricht dann dem Speicher des Computers.
In Python​
Die Zuweisung
a = 10
kann im neuen Modell also so dargestellt werden:
Das rechteckige Kästchen mit dem Namen a
ist die Variable oder Etikette. Der Pfeil ist die Referenz oder Schnur und das runde Kästchen ist das Objekt mit dem Wert 10
.
Diese Modell hat entscheidende Konsequenzen, welche wir uns im folgenden anschauen wollen.
Zuweisung von Variable zu Variable​
Weist man eine Variable einer anderen zu, so läuft dies darauf hinaus, dass Etiketten mit anderen Objekten verbunden werden.
Die Zuweisung
b = a
fĂĽhrt im neuen Modell dazu, dass die beiden Variablen a
und b
jetzt beide auf das Objekt mit dem Wert 10
zeigen.
Erst, wenn man einer Variablen einen anderen Wert zuweist, so zeigen beide Variablen auf verschiedene Objekte.
b = 11
fĂĽhrt zu:
Listen sind Objekte​
Eine Liste ist ein Objekt, welches nicht nur einen Wert enthalten kann, sondern viele. Man kann sich eine Liste als Kette von Elementen denken. Dabei enthält jedes Element eine Referenz auf das unmittelbar nachfolgende Element und zusätzlich eine Referenz auf den in diesem Element gespeicherten Wert. Der Wert selber ist dann natürlich wieder in einem Objekt gekapselt. Die Elemente sind also gleichzeitig so etwas, wie Objekte und Variable.
Das Resultat der Zuweisung
a = [1, 2, 3]
kann in unserem neuen Modell folglich so gezeichnet werden:
Wird die Variable a
einer Variablen b
zugewiesen
b = a
fĂĽhrt diese zu folgender Situation
Wenn wir in einem Programm
a[1]
schreiben, so wird über das Kärtchen mit dem Namen a
auf das erste Element der Liste zugegriffen und von aus auf der Kette der Element entlang, bis das Element mit dem Index 1 erreicht ist. Von da wird auf das dem Elment angehängte Objekt zugegriffen. Im obigen Fall ist das die Zahl2
.
Interessant ist nun der Fall, wo ein einzelnes Element der Liste verändert wird:
b[0] = b[0] + 1
Im Modell wird unmittelbar klar, dass es keine Rolle spielt, ob wir die Liste ĂĽber die Variable a
oder b
ansprechen. Es gibt nur die eine Liste. a[0]
und b[0]
beziehen sich auf ein und dasselbe Element.
Aufgabe​
Laden Sie zur Illustration das folgenden Snippet auf Ihren Computer und fĂĽhren Sie es aus.
Hintergrund​
Das neue Modell fĂĽr Variablen hat folgenden Hintergrund:
Alle Daten, mit welchen ein Programm arbeitet, mĂĽssen im RAM (Random Access Memory) des Computers gespeichert werden. Dies ist derjenige Speicher des Computer, der sehr schnell arbeitet, aber beim Ausschalten des Computers alle gespeicherten Daten verliert.
Man kann sich das RAM alls riesige Tabelle mit einer Spalte vorstellen. Jede Zelle in der Tabelle umfasst 1 Byte (8 bit) und kann also ein Zahl von 0 bis 255 ( Zustände) speichern. Die Zellen sind von 0 beginnend durchnummeriert. Die Nummer einer Zelle wird als deren Adresse bezeichnet. Wenn der Prozessor auf eine bestimmte Zelle zugreifen will, um dort eine Zahl zu lesen oder zu schreiben, so muss er diese Adresse kennen.
Wenn in einem Programm eine Variable gebraucht wird, so läuft das darauf hinaus, dass das Programm auf eine Zelle mit einer bestimmten Adresse zugreift. Jede Variable hat also ihren festen Platz im RAM. Beim Start des Programms wird dieser Platz für alle globalen Variablen eines Programms dauerhaft festgelegt. Bei lokalen Variablen (Variablen in Funktionen und Funktionsparameter) wird der Platz unmittelbar nach dem Aufruf einer Funktion festgelegt.
Damit wir nun in unseren Programmen nicht mit physischen Speicheradressen arbeiten mĂĽssen, welche wir ja zum Zeitpunkt des Programmierens gar nicht kennen, verwendet man Variablennamen als Platzhalter.
Speicherbedarf von Variablen​
Je nachdem, welche Werte in einer Variablen gespeichert werden sollen braucht es mehr oder weniger Platz, sprich mehr oder weniger Speicherzellen. Zum Speichern einer Zahl mit Kommastellen (Datentyp float
in Python) werden oft 64 bit (8 Byte) verwendet. In vielen Programmiersprachen werden auch fĂĽr ganze Zahlen (Datentyp int
) eine feste Anzahl Bytes verwendet (z.B. 4 Byte). Im Speicher könnte das dann so aussehen:
Neben den Datentypen mit fester Anzahl Bytes gibt es aber auch Datentypen, deren Speicherbedarf variieren kann. Z.B. beansprucht ein Text (datentyp str
für String) je nach Inhalt mehr oder weniger Bytes zu seiner Speicherung. Zusätzlich ist es in Python auch so, dass eine Variable im Verlaufe der Programmausführung Werte von unterschiedlichen Datentypen speichern kann. Z.B. startet die Variable mit einer ganzen Zahl und wechselt dann später zu einem Text. Das könnte dazu führen, dass am Ort der Variablen plötzlich mehr Speicher gebraucht wird. Was aber, wenn dort kein Speicher mehr frei ist, weil die Variablen dicht gepackt sind?
Referenzen und Objekte​
Um das obige Problem zu umgehen, verwendet Python ein indirektes Verfahren, um von einer Variable zu den gespeicherten Werten zu gelangen:
-
Am Ort der Variablen ist nur eine Adresse gespeichert. Unter dieser Adresse findet man dann den eigentlichen Wert. Diese Adresse wird als Referenz bezeichnet.
-
Der eigentliche Wert, kann nun beliebig gross sein. Sie werden in Python (und vielen anderen Programmiersprachen) als Objekt bezeichnet. Bei der Speicherung eines neuen Objektes sucht Python im Speicher nach einer Stelle, wo es genug Platz hat und trägt dan bei der Variablen die Adresse des Objektes ein. Das sieht dann so aus:
In Python werden alle Daten als Objekte gespeichert.
Zurück zu den Listen​
Objekte können wiederum Referenzen auf andere Objekte enthalten. So werden beispielsweise Listen gebildet. Eine Liste besteht aus Elementobjekten, welche einerseits eine Referenz auf den an dieser Stelle in der Liste gespeicherte Wert (auch ein Objekt, siehe oben) enthält und andererseits eine Referenz auf das unmittelbar nachfolgende Elementobjekt ethält.
Das sieht dann so aus:
Referenzen