Wenn Sie schreiben [x]*3
erhalten Sie im Wesentlichen die Liste [x, x, x]
. Das heißt, eine Liste mit 3 Verweisen auf denselben x
. Wenn Sie dann diese einzelne Änderung x
sie ist durch alle drei Verweise auf sie sichtbar:
x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(l[0]): {id(l[0])}\n"
f"id(l[1]): {id(l[1])}\n"
f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
Um dies zu beheben, müssen Sie sicherstellen, dass Sie an jeder Position eine neue Liste erstellen. Eine Möglichkeit, dies zu tun, ist
[[1]*4 for _ in range(3)]
die eine Neubewertung vornehmen wird [1]*4
jedes Mal, anstatt es einmal auszuwerten und 3 Verweise auf 1 Liste zu machen.
Sie fragen sich vielleicht, warum *
kann keine unabhängigen Objekte erzeugen, wie es das Listenverständnis tut. Das liegt daran, dass der Multiplikationsoperator *
wirkt auf Objekte, ohne Ausdrücke zu sehen. Wenn Sie *
zu multiplizieren [[1] * 4]
von 3, *
sieht nur die 1-Element-Liste [[1] * 4]
auswertet, nicht die [[1] * 4
Ausdruckstext. *
keine Ahnung hat, wie man Kopien von diesem Element anfertigt, keine Ahnung, wie man es neu bewertet [[1] * 4]
und keine Ahnung, dass Sie überhaupt Kopien wollen, und im Allgemeinen gibt es vielleicht nicht einmal eine Möglichkeit, das Element zu kopieren.
Die einzige Möglichkeit *
besteht darin, neue Verweise auf die bestehende Teilliste zu erstellen, anstatt zu versuchen, neue Teillisten zu erstellen. Alles andere wäre inkonsistent oder würde eine umfassende Umgestaltung grundlegender Entscheidungen zum Sprachdesign erfordern.
Im Gegensatz dazu wird bei einem Listenverständnis der Elementausdruck bei jeder Iteration neu ausgewertet. [[1] * 4 for n in range(3)]
bewertet neu [1] * 4
jedes Mal aus demselben Grund [x**2 for x in range(3)]
bewertet neu x**2
jedes Mal. Jede Bewertung von [1] * 4
erzeugt eine neue Liste, so dass das Listenverständnis das tut, was Sie wollten.
Im Übrigen, [1] * 4
kopiert auch nicht die Elemente von [1]
aber das spielt keine Rolle, da Ganzzahlen unveränderlich sind. Sie können nicht etwas tun wie 1.value = 2
und verwandeln eine 1 in eine 2.
0 Stimmen
Es ist zu beachten, dass die gleiche Logik für eine Liste von Dicts gilt, da das Problem des Aliasing eines veränderlichen Objekts grundsätzlich dasselbe ist. Siehe stackoverflow.com/questions/46835197/ für eine spezifischere Frage.
1 Stimmen
Gibt es spezifischere Fragen für den Fall, dass die Liste der Listen auf andere Weise erstellt wird (aber das gleiche Problem auftritt)? Zum Beispiel durch die Verwendung von
.append
in einer Schleife?0 Stimmen
Siehe auch stackoverflow.com/questions/2612802 für eine Frage, die sich auf die Vermeidung dieser Art von Aliasing im Nachhinein konzentriert.
1 Stimmen
Verwandt: nedbatchelder.com/text/namen.html