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))[1, 2, 3, 4] True True
Bei 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)5 6
Flache 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)[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ängigoriginal: [[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)[[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][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))[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)True False
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
Aufgabe
Erzeuge ein 3×3-Gitter aus Nullen, setze die Mitte auf 5 und gib das Gitter zeilenweise aus.