EMZETT.
Login

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

Kapitel 20 von 44 im Kurs Python. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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
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)

Ausgabe:

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)

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ängig

Ausgabe:

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 False

Tipp

Verlasse dich bei Zahlen und Texten nie auf is. Dass 256 is 256 manchmal True ist, ist ein Implementierungsdetail von Python.

Merke

  • Variablen sind Namen, die auf Objekte zeigen; b = a kopiert nur den Verweis
  • Flache Kopie: .copy() oder [:]; tiefe Kopie: copy.deepcopy()
  • [[0] * 3] * 3 erzeugt dieselbe innere Liste dreimal
  • Niemals [] oder {} als Standardwert eines Parameters verwenden; None nehmen
  • == vergleicht Werte, is vergleicht Objekte

Übungsaufgabe

Erzeuge ein 3×3-Gitter aus Nullen, setze die Mitte auf 5 und gib das Gitter zeilenweise aus.

Quiz zur Selbstkontrolle

) 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