Routineaufgaben mit Python automatisieren. Al Sweigart
Читать онлайн книгу.mag Ihnen merkwürdig vorkommen. Schließlich hat der Code nur die Liste cheese bearbeitet. Aber es scheint, dass beide Listen verändert worden sind!
Wenn Sie die Liste erstellen (
Gewöhnlich wird gesagt, dass Sie sich Variablen als Kisten vorstellen können, die Werte enthalten. Das ist hier jedoch nicht ganz korrekt, denn in Wirklichkeit enthalten die Variablen gar nicht die Listen selbst, sondern nur Verweise darauf. (Diese Verweise tragen ID-Nummern, die Python intern verwendet, aber darum brauchen wir uns nicht zu kümmern.) Abb. 4–4 zeigt, was geschieht, wenn eine Liste der Variablen spam zugewiesen wird.
Abb. 4–4Mit spam = [0, 1, 2, 3, 4, 5] wird ein Verweis auf die Liste gespeichert, aber nicht die Liste selbst.
In Abb. 4–5 sehen Sie, wie der Verweis in spam zu cheese kopiert wird. Das bedeutet aber nur, dass ein neuer Verweis erstellt und in cheese gespeichert wird, aber keine neue Liste. Beide verweisen auf dieselbe Liste.
Abb. 4–5Mit spam = cheese wird der Verweis kopiert, aber nicht die Liste.
Wenn Sie die Liste ändern, auf die cheese verweist, ändern Sie damit auch die Liste, auf die spam verweist, da es sich dabei um ein und dieselbe handelt. Das können Sie in Abb. 4–6 erkennen.
Abb. 4–6cheese[1] = 'Hello!' ändert die Liste, auf die beide Variablen verweisen.
Python-Variablen enthalten zwar eigentlich nur Verweise auf Werte, doch umgangssprachlich wird oft die Formulierung gebraucht, dass eine Variable einen Wert enthält.
Identität und die Funktion id()
Vielleicht fragen Sie sich, warum das merkwürdige Verhalten, das Sie im vorhergehenden Abschnitt kennengelernt haben, nicht auch bei unveränderbaren Werten wie Integern oder Strings vorkommt. Um das besser zu verstehen, können wir die Python-Funktion id() heranziehen. Alle Werte in Python haben eine eindeutige Identität, die Sie mit dieser Funktion abrufen können. Geben Sie folgenden Code in die interaktive Shell ein:
>>> id('Howdy') # Auf Ihrem Computer wird eine andere Zahl zurückgegeben
44491136
Wenn Python id('Howdy') ausführt, wird der String 'Howdy' im Arbeitsspeicher angelegt und die numerische Adresse seines Speicherorts zurückgegeben. Python wählt die Adresse danach aus, welche Bytes auf dem Computer gerade frei sind. Daher erhalten Sie jedes Mal, wenn Sie diesen Code ausführen, ein anderes Ergebnis.
Wie alle Strings ist auch 'Howdy' unveränderbar. Wenn Sie einen String in einer Variablen ändern, wird in Wirklichkeit ein neues Stringobjekt an einer anderen Stelle im Arbeitsspeicher angelegt und der Verweis darauf in der Variablen festgehalten. Mit dem folgenden Beispielcode können Sie beobachten, wie sich die Identität des Strings ändert, auf den bacon verweist:
>>> bacon = 'Hello'
>>> id(bacon)
44491136
>>> bacon += ' world!' # Erstellt neuen String aus 'Hello' und ' world!'
>>> id(bacon) # bacon verweist jetzt auf einen ganz anderen String
44609712
Listen dagegen sind veränderbar. Die Methode append() erstellt kein neues Listenobjekt, sondern verändert das vorhandene. Wir sprechen hier von einer unmittelbaren oder direkten Änderung des Objekts.
>>> eggs = ['cat', 'dog'] # Erstellt eine neue Liste
>>> id(eggs)
35152584
>>> eggs.append('moose') # append() ändert die Liste direkt
>>> id(eggs) # eggs verweist immer noch auf dieselbe Liste
35152584
>>> eggs = ['bat', 'rat', 'cow'] # Erstellt eine neue Liste mit neuer
Identität
>>> id(eggs) # eggs verweist jetzt auf eine ganz andere Liste
44409800
Wenn zwei Variablen auf dieselbe Liste verweisen (wie spam und eggs im vorherigen Abschnitt) und die Liste geändert wird, dann sind davon beide Variablen betroffen. Die Listenmethoden append(), extend(), remove(), sort(), reverse() usw. ändern Listen direkt.
Pythons automatische Garbage Collection entfernt alle Werte, auf die keine Variablen mehr verweisen, um Platz im Arbeitsspeicher freizumachen. Über diese Garbage Collection müssen Sie sich keine Gedanken machen, was eine gute Sache ist, denn durch die manuelle Speicherverwaltung in anderen Programmiersprachen schleichen sich häufig Fehler ein.
Verweise übergeben
Die Kenntnis von Verweisen ist unverzichtbar, um zu verstehen, wie Argumente an Funktionen übergeben werden. Bei einem Funktionsaufruf werden die Werte der Argumente in die Parametervariablen kopiert. Bei Listen als Argumenten (und bei Dictionaries, die ich im nächsten Kapitel beschreiben werde) bedeutet das, dass für den Parameter eine Kopie des Verweises verwendet wird. Um zu erkennen, was das bedeutet, geben Sie den folgenden Code im Dateieditor ein und speichern ihn als passingReference.py:
def eggs(someParameter):
someParameter.append('Hello')
spam = [1, 2, 3]
eggs(spam)
print(spam)
Beim Aufruf von eggs() wird kein Rückgabewert verwendet, um spam einen neuen Wert zuzuweisen. Stattdessen wird die Liste unmittelbar geändert. Dieses Programm führt zu folgender Ausgabe:
[1, 2, 3, 'Hello']
Obwohl spam und someParameter getrennte Verweise enthalten, verweisen doch beide auf dieselbe Liste. Daher wirkt sich der Methodenaufruf append('Hello') innerhalb der Funktion auch dann noch auf die Liste aus, wenn der Funktionsaufruf die Steuerung zurückgegeben hat.
Merken Sie sich dieses Verhalten. Wenn Sie nicht beachten, dass Python Listen- und Dictionary-Variablen auf diese Weise handhabt, kann das zu verwirrenden Fehlern