Kurz: Dieses Kapitel räumt mit einer der häufigsten Fehlerquellen auf: Was passiert eigentlich bei b = a, wenn a eine Liste ist?
Teil des Kurses Python
Dieses Kapitel räumt mit einer der häufigsten Fehlerquellen auf: Was passiert eigentlich bei b = a, wenn a eine Liste ist?
Namen sind Verweise
In Python ist eine Variable kein Kasten mit einem Wert, sondern ein Name, der auf ein Objekt zeigt. Bei veränderlichen Objekten (Listen, Dictionaries, Mengen) zeigen zwei Namen dann auf dasselbe Objekt:
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(a is b)
print(id(a) == id(b))Ausgabe:
[1, 2, 3, 4]
True
TrueBei unveränderlichen Werten (Zahlen, Texte, Tupel) fällt das nie auf, denn eine “Änderung” erzeugt dort immer ein neues Objekt:
x = 5
y = x
y += 1
print(x, y)Ausgabe:
5 6Flache Kopie
liste.copy(), liste[:] und list(liste) erzeugen eine neue Liste mit denselben Elementen. Das reicht, solange die Elemente selbst unveränderlich sind:
a = [1, 2, 3]
b = a.copy()
b.append(4)
print(a, b)Ausgabe:
[1, 2, 3] [1, 2, 3, 4]Tiefe Kopie
Enthält die Liste selbst Listen, teilen sich die Kopien die inneren Listen. Dann brauchst du copy.deepcopy():
import copy
original = [[1, 2], [3, 4]]
flach = original.copy()
tief = copy.deepcopy(original)
original[0].append(99)
print("original:", original)
print("flach: ", flach) # die innere Liste ist dieselbe!
print("tief: ", tief) # unabhängigAusgabe:
original: [[1, 2, 99], [3, 4]]
flach: [[1, 2, 99], [3, 4]]
tief: [[1, 2], [3, 4]]Falle: Listen mit * vervielfachen
falsch = [[0] * 3] * 3 # dreimal DIESELBE innere Liste
falsch[0][0] = 1
print(falsch)
richtig = [[0] * 3 for _ in range(3)] # drei getrennte Listen
richtig[0][0] = 1
print(richtig)Ausgabe:
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]Falle: veränderliche Standardwerte
Ein veränderlicher Standardwert in einer Funktion wird nur einmal erzeugt und bei jedem Aufruf wiederverwendet:
def sammle(wert, liste=[]): # Vorsicht!
liste.append(wert)
return liste
print(sammle(1))
print(sammle(2)) # überraschend: [1, 2]Ausgabe:
[1]
[1, 2]Richtig ist None als Standardwert:
def sammle(wert, liste=None):
if liste is None:
liste = []
liste.append(wert)
return liste
print(sammle(1))
print(sammle(2))Ausgabe:
[1]
[2]Gleichheit und Identität
== fragt, ob zwei Werte gleich sind, is fragt, ob es dasselbe Objekt ist:
a = [1, 2]
b = [1, 2]
print(a == b, a is b)Ausgabe:
True FalseTipp
Verlasse dich bei Zahlen und Texten nie auf
is. Dass256 is 256manchmalTrueist, ist ein Implementierungsdetail von Python.
Merke
- Variablen sind Namen, die auf Objekte zeigen;
b = akopiert nur den Verweis - Flache Kopie:
.copy()oder[:]; tiefe Kopie:copy.deepcopy() [[0] * 3] * 3erzeugt dieselbe innere Liste dreimal- Niemals
[]oder{}als Standardwert eines Parameters verwenden;Nonenehmen ==vergleicht Werte,isvergleicht Objekte
Übungsaufgabe
Erzeuge ein 3×3-Gitter aus Nullen, setze die Mitte auf 5 und gib das Gitter zeilenweise aus.
Quiz zur Selbstkontrolle
Was bewirkt b = a, wenn a eine Liste ist?
- b zeigt auf dieselbe Liste wie a (richtig)
- Es entsteht eine unabhängige Kopie
- Die Liste wird verdoppelt
- a wird gelöscht
Wann brauchst du copy.deepcopy()?
- Wenn die Liste selbst veränderliche Elemente wie Listen enthält (richtig)
- Wenn die Liste nur Zahlen enthält
- Immer, wenn du kopieren willst
- Nur bei Texten
) problematisch?
- Die Liste wird einmal erzeugt und bei jedem Aufruf wiederverwendet (richtig)
- Sie ist zu langsam
- Leere Listen sind verboten
- Der Standardwert wird ignoriert
Weiter im Kurs
Zurück: Dictionaries
Weiter: Funktionen
Alle Kapitel: Python im Überblick