===== Objekte, Variablen und Mutabilität in Python ===== Intuitiv wissen wir aus unserer bisherigen Programmiererfahrung, was eine Variable ist. Trotzdem lohnt es sich, den Begriff der //Variablen// in der Informatik bzw. genauer in Python präzise zu definieren((er unterscheidet sich vom Begriff der Variablen in der Mathematik, vgl. [[https://en.wikipedia.org/wiki/Variable_(mathematics)]])). (Genau habe ich das auch erst beim Schreiben dieses Textes gelernt - man kommt also ziemlich weit mit dem intuitiven Begriff. Die offizielle Dokumentation ist [[https://docs.python.org/3/reference/datamodel.html|hier]] und enthält natürlich viel mehr Details als mein Text. Dort wird kaum von Variablen gesprochen, sondern meist von Namen, die an Objekte gebunden werden.) Ein sogenanntes //Objekt// in Python dient dem Speichern von Daten und besteht aus drei Informationen: * einem Typ * einem Wert. * einer Identität (diese mag man sich als "Speicheradresse" vorstellen) Eine //Variable// in Python ist ein Name, der mit einem Objekt verbunden ist, also ein //benanntes Objekt//. Präziser ist eine //Variable// ein Name zusammen mit einem Verweis auf ein Objekt. Beispielsweise erzeugt * ''"abc"'' ein Objekt vom Typ //string//, dessen //Wert// die Zeichenkette abc ist (die Identität wird beim Programmablauf bestimmt; der Programmierer hat da keinen Einfluss). * ''3'' ein Objekt vom Typ //integer//, dessen //Wert// die Zahl 3 ist. * ''[1,2,3]'' ein Objekt vom Typ //list//, dessen //Wert// die Aufzählung/Liste [1,2,3] von Zahlen bzw. genaugenommen von Objekten vom Typ //integer// ist. Die folgenden drei Zuweisungsoperatoren ''='' definieren Variablen (mit den Namen) ''x'', ''y'' und ''z'', die jeweils auf das rechts des Zuweisungsoperators ''='' angegebene Objekt verweisen. x = "abc" y = 3 z = [1,2,3] Taucht eine Variable (also etwa ''x'') später irgendwo im Programm auf (aber nicht links von einem Zuweisungsoperator ''=''), wird dort mit dem Objekt gearbeitet, auf das diese Variable verweist. Typ, Wert und Identität der Variablen ''x'' (oder genauer gesagt des Objektes, auf das diese Variable verweist) können wie folgt ausgeben werden (analog für ''y'' und ''z''): print(type(x)) print(x) print(id(x)) Man mag sich hier wundern, warum nicht etwas wie ''print(value(x))'' in der zweiten Zeile steht. Der Befehl ''print'' extrahiert aber automatisch den Wert aus dem angegebenen Objekt((Genauer haben alle gängigen Objekte eine "Anzeigefunktion", die meist den Wert in geeigneter Weise als string liefert; diese Anzeigefunktion von ''x'' ruft ''print'' intern auf.)). Bildlich stellt ich mir die soeben definierten Variablen wie folgt als Verweise vor (die Identitäten sind mehr oder weniger zufällig): {{:lehrkraefte:snr:informatik:python:variablen-in-python.jpg?direct&400|}} Objekte sind entweder //immutable// oder //mutable// sind (deutsch //unveränderlich//=//immutabel// oder //veränderlich//=//mutabel//). * Immutable Objekte kann man nach ihrer Erzeugung NICHT verändern. * Mutable Objekte kann man nach ihrer Erzeugung verändern. Ob ein Objekt //immutable// oder //mutable// ist, hängt nur von seinem Typ ab. Die Entwickler von Python haben folgendes festgelegt: | Jedes Objekt vom Typ | integer, float, string (auch tuple, set) | list | | ist ^ immutable ^ mutable | Hier noch zwei Beispiele, die Teilaspekte illustrieren. Betrachte das (etwas dumme) Programm. a = 4 a = 5 Hier ändert sich die Variable ''a''. Dies hat aber nichts mit der gerade erklärten Immutabilität/Mutabilität von Objekten zu tun. Die Variable ''a'' verweist zuerst auf das immutable Objekt 4, dann auf das immutable Objekt 5. Da beim Programmablauf in der zweiten Zeile keine Variable mehr auf das Objekt 4 verweist, kann der entsprechende Speicherbereich freigegeben werden (garbage collection). Beim Ablauf des folgenden Programms auf meinem Rechner haben die Variablen ''x'' und ''y'' zunächst dieselbe Identität, später haben sie verschiedene Identitäten. x = 2 y = 2 z = 3 print('id: ' + str(id(x)) + '| type: ' + str(type(x)) + '| value: ' + str(x)) print('id: ' + str(id(y)) + '| type: ' + str(type(y)) + '| value: ' + str(y)) print('id: ' + str(id(z)) + '| type: ' + str(type(z)) + '| value: ' + str(z)) x = [2,3] y = [2,3] z = [3,4] print('id: ' + str(id(x)) + '| type: ' + str(type(x)) + '| value: ' + str(x)) print('id: ' + str(id(y)) + '| type: ' + str(type(y)) + '| value: ' + str(y)) print('id: ' + str(id(z)) + '| type: ' + str(type(z)) + '| value: ' + str(z)) Dieses Verhalten ist in der offiziellen Referenz erklärt. Ich zitiere aus dem Abschnitt vor [[https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy]]: "for immutable types, operations that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed". ===== Nachträglich gefunden ===== Auf der Wikipedia-Seite https://en.wikipedia.org/wiki/Data_type findet sich die nützliche Abbildung https://en.wikipedia.org/wiki/Data_type#/media/File:Python_3._The_standard_type_hierarchy.png. ===== Link zurück zu Listen ===== [[lehrkraefte:snr:informatik:python:listen|Zurück zu Listen]]