Wenn Sie schreiben, erhalten [x]*3
Sie im Wesentlichen die Liste [x, x, x]
. Das heißt, eine Liste mit 3 Verweisen darauf x
. Wenn Sie diese Single dann ändern x
, ist sie über alle drei Verweise darauf 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. Ein Weg, dies zu tun, ist
[[1]*4 for _ in range(3)]
Dies wird [1]*4
jedes Mal neu bewertet, anstatt es einmal zu bewerten und 3 Verweise auf 1 Liste zu machen.
Sie fragen sich vielleicht, warum *
unabhängige Objekte nicht so erstellt werden können wie das Listenverständnis. Dies liegt daran, dass der Multiplikationsoperator *
Objekte bearbeitet, ohne Ausdrücke zu sehen. Wenn Sie mit 3 *
multiplizieren [[1] * 4]
, wird *
nur die 1-Element-Liste [[1] * 4]
ausgewertet, nicht der [[1] * 4
Ausdruckstext. *
hat keine Ahnung, wie Kopien dieses Elements erstellt werden sollen, keine Ahnung, wie eine Neubewertung vorgenommen werden soll [[1] * 4]
, und keine Ahnung, dass Sie überhaupt Kopien wünschen, und im Allgemeinen gibt es möglicherweise nicht einmal eine Möglichkeit, das Element zu kopieren.
Die einzige Möglichkeit *
besteht darin, neue Verweise auf die vorhandene Unterliste zu erstellen, anstatt zu versuchen, neue Unterlisten zu erstellen. Alles andere wäre inkonsistent oder würde eine umfassende Neugestaltung grundlegender Entscheidungen zum Sprachdesign erfordern.
Im Gegensatz dazu bewertet ein Listenverständnis den Elementausdruck bei jeder Iteration neu. [[1] * 4 for n in range(3)]
wird [1] * 4
jedes Mal aus demselben Grund [x**2 for x in range(3)]
neu bewertet, x**2
jedes Mal neu bewertet . Jede Auswertung von [1] * 4
generiert eine neue Liste, sodass das Listenverständnis das tut, was Sie wollten.
Kopiert übrigens [1] * 4
auch nicht die Elemente von [1]
, aber das spielt keine Rolle, da Ganzzahlen unveränderlich sind. Sie können so etwas nicht tun 1.value = 2
und eine 1 in eine 2 verwandeln.
[x]*3
3 Referenzen speichern wie[x, x, x]
ist nur dann richtig, wennx
es veränderlich ist. Dies funktioniert nicht für zBa=[4]*3
, wo nacha[0]=5
,a=[5,4,4].
[4]*3
ist im Wesentlichen äquivalent zux = 4; [x, x, x]
. Es ist jedoch wahr, dass dies niemals ein Problem verursachen wird , da4
es unveränderlich ist. Auch Ihr anderes Beispiel ist nicht wirklich ein anderer Fall.a = [x]*3; a[0] = 5
verursacht keine Probleme, auch wennx
es veränderlich ist, da Sie nicht modifizierenx
, sondern nur modifizierena
. Ich würde meine Antwort nicht als irreführend oder falsch beschreiben - Sie können sich einfach nicht in den Fuß schießen, wenn Sie mit unveränderlichen Objekten zu tun haben.x = 1000; lst = [x]*2; lst[0] is lst[1]
->True
. Python unterscheidet hier überhaupt nicht zwischen veränderlichen und unveränderlichen Objekten.Live Python Tutor Visualisieren
quelle
x
auf das verwiesen wird . Wenn Sie ein global eindeutiges Objekt mitx = object()
matrix = [[x] * 2]
matrix[0][0] is matrix[0][1]
list
). Wenn also arow = [x] * 2
als amatrix = [row] * 2
beide Zeilen genau dasselbe Objekt sind und sich jetzt zu einer Zeile ändern,matrix[0][0] = y
spiegeln sich diese plötzlich in der anderen(matrix[0][0] is matrix[1][0]) == True
Genau das würden Sie erwarten. Zerlegen wir, was hier passiert:
Du schreibst
Dies entspricht:
Dies bedeutet, dass
lst
es sich um eine Liste mit 3 Elementen handelt, auf die alle verweisenlst1
. Dies bedeutet, dass die beiden folgenden Zeilen äquivalent sind:Da
lst[0]
ist nichts alslst1
.Um das gewünschte Verhalten zu erhalten, können Sie das Listenverständnis verwenden:
In diesem Fall wird der Ausdruck für jedes n neu ausgewertet, was zu einer anderen Liste führt.
quelle
id(lst[0][0])
undid(lst[1][0])
oder sogarid(lst[0])
undid(lst[1])
oder auch:
Erstellt eine Liste, die
[1,1,1,1]
dreimal auf die interne Liste verweist - nicht drei Kopien der inneren Liste. Jedes Mal, wenn Sie die Liste ändern (an einer beliebigen Position), wird die Änderung dreimal angezeigt.Es ist das gleiche wie in diesem Beispiel:
wo es wahrscheinlich etwas weniger überraschend ist.
quelle
Wenn Sie Python-2.x verwenden
xrange()
, wird neben der akzeptierten Antwort, die das Problem korrekt erklärt hat, innerhalb Ihres Listenverständnisses ein Generator zurückgegeben, der effizienter ist (range()
in Python 3 erledigt er den gleichen Job)_
als die Wegwerfvariablen
:Als viel pythonischere Methode können Sie auch
itertools.repeat()
ein Iteratorobjekt aus wiederholten Elementen erstellen:PS Mit numpy, wenn Sie eine Reihe von Einsen oder Nullen erstellen möchten , können Sie verwenden ,
np.ones
undnp.zeros
und / oder für andere Nummer verwendennp.repeat()
:quelle
myList = [[1]*4] * 3
Erstellt ein Listenobjekt[1,1,1,1]
im Speicher und kopiert seine Referenz dreimal. Dies entsprichtobj = [1,1,1,1]; myList = [obj]*3
. Jede Änderung anobj
wird an drei Stellen wiedergegeben, woobj
immer in der Liste darauf verwiesen wird. Die richtige Aussage wäre:oder
Hierbei ist zu beachten, dass der
*
Operator hauptsächlich zum Erstellen einer Liste von Literalen verwendet wird . Obwohl1
unveränderlich,obj =[1]*4
wird immer noch eine Liste von1
viermal wiederholten zu erstellen[1,1,1,1]
. Wenn jedoch auf ein unveränderliches Objekt Bezug genommen wird, wird das Objekt mit einem neuen überschrieben.Dies bedeutet, wenn wir dies tun
obj[1]=42
,obj
wird dies[1,42,1,1]
nicht so sein,wie manche annehmen. Dies kann auch überprüft werden:[42,42,42,42]
quelle
obj[2] = 42
die Referenz ersetzt bei Index2
, wie zum Mutieren des durch diesen Index referenzierten Objekts gegenüber , das ist , wasmyList[2][0] = ...
bedeutet (myList[2]
eine Liste, und die assigment Abspaltungen die Referenz bei Index 0 in THA - Liste). Natürlich sind ganze Zahlen nicht wandelbar, aber viele Objekttypen sind . Und beachten Sie, dass die[....]
Notation der Listenanzeige auch eine Form der wörtlichen Syntax ist! Verwechseln Sie keine zusammengesetzten (wie Listen) und skalaren Objekte (wie Ganzzahlen) mit veränderlichen oder unveränderlichen Objekten.Python-Container enthalten Verweise auf andere Objekte. Siehe dieses Beispiel:
In dieser
b
Liste befindet sich ein Element, das auf die Liste verweista
. Die Listea
ist veränderlich.Die Multiplikation einer Liste mit einer Ganzzahl entspricht dem mehrfachen Hinzufügen der Liste zu sich selbst (siehe allgemeine Sequenzoperationen ). Fahren Sie also mit dem Beispiel fort:
Wir können sehen, dass die Liste
c
jetzt zwei Verweise auf die Liste enthält,a
die äquivalent zu sindc = b * 2
.Die Python-FAQ enthält auch Erklärungen zu diesem Verhalten: Wie erstelle ich eine mehrdimensionale Liste?
quelle
In einfachen Worten, dies geschieht, weil in Python alles als Referenz funktioniert. Wenn Sie also eine Liste mit Listen auf diese Weise erstellen, treten im Grunde solche Probleme auf.
Um Ihr Problem zu lösen, können Sie eine der folgenden Aktionen ausführen : 1. Verwenden Sie die numpy-Array- Dokumentation für numpy.empty. 2. Hängen Sie die Liste an, sobald Sie zu einer Liste gelangen. 3. Sie können auch das Wörterbuch verwenden, wenn Sie möchten
quelle
Lassen Sie uns Ihren Code folgendermaßen umschreiben:
Führen Sie dann den folgenden Code aus, um alles klarer zu machen. Was der Code tut, ist im Grunde das
id
s der erhaltenen Objekte zu drucken , dieund hilft uns, sie zu identifizieren und zu analysieren, was passiert:
Und Sie erhalten folgende Ausgabe:
Lassen Sie uns nun Schritt für Schritt gehen. Sie haben
x
welche1
und eine einzelne Elementlistey
enthältx
. Ihr erster Schritt besteht dariny * 4
, eine neue Liste zu erhaltenz
,[x, x, x, x]
dh im Grunde genommen wird eine neue Liste erstellt, die 4 Elemente enthält, die auf das ursprünglichex
Objekt verweisen . Der Netzschritt ist ziemlich ähnlich. Sie tun im Grundez * 3
, was ist[[x, x, x, x]] * 3
und zurückkehrt[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
, aus dem gleichen Grund wie für den ersten Schritt.quelle
Ich denke, jeder erklärt, was passiert. Ich schlage einen Weg vor, um es zu lösen:
myList = [[1 for i in range(4)] for j in range(3)]
print myList
Und dann haben Sie:
quelle
Der Versuch, es anschaulicher zu erklären,
Operation 1:
Operation 2:
Es wurde festgestellt, warum durch Ändern des ersten Elements der ersten Liste nicht das zweite Element jeder Liste geändert wurde. Das liegt daran, dass es sich
[0] * 2
wirklich um eine Liste mit zwei Zahlen handelt und ein Verweis auf 0 nicht geändert werden kann.Wenn Sie Klonkopien erstellen möchten, versuchen Sie Operation 3:
Ein weiterer interessanter Weg, um Klonkopien zu erstellen, ist Operation 4:
quelle
@spelchekr aus der Python- Listenmultiplikation : [[...]] * 3 erstellt 3 Listen, die sich bei Änderungen gegenseitig spiegeln, und ich hatte die gleiche Frage zu "Warum erstellt nur die äußere * 3 mehr Referenzen, während die innere nicht ? Warum ist nicht alles 1s? "
Hier ist meine Erklärung, nachdem ich den obigen Code ausprobiert habe:
*3
erstellt auch Referenzen, aber seine Referenzen sind unveränderlich.[&0, &0, &0]
Wennli[0]
Sie sie ändern möchten0
, können Sie keine zugrunde liegende Referenz von const int ändern. Sie können also einfach die Referenzadresse in die neue ändern&1
.ma=[&li, &li, &li]
undli
ist veränderlich. Wenn Sie also aufrufenma[0][0]=1
, ist ma [0] [0] gleich&li[0]
, sodass alle&li
Instanzen ihre erste Adresse in ändern&1
.quelle
Mit der eingebauten Listenfunktion können Sie dies tun
quelle
a.insert(0,[5,1,1,1])