Liste der Listen änderungen über Teillisten unerwartet
Ich brauchte, um eine Liste zu erstellen von Listen in Python, also tippte ich die folgenden:
myList = [[1] * 4] * 3
Die Liste sah so aus:
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Dann habe ich veränderte die inneren Werte:
myList[0][0] = 5
Nun meine Liste sieht wie folgt aus:
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
ist nicht das, was ich wollte oder erwartete. Kann mir bitte jemand erklären, was Los ist, und wie man um ihn herum?
InformationsquelleAutor Charles Anderson | 2008-10-27
Schreibe einen Kommentar Antworten abbrechen
Du musst angemeldet sein, um einen Kommentar abzugeben.
Beim schreiben
[x]*3
erhalten Sie im wesentlichen der Liste[x, x, x]
. Das heißt, eine Liste mit 3 Referenzen auf das gleichex
. Wenn Sie dann ändern diese einzelnenx
es ist sichtbar über alle drei Referenzen.Um es zu beheben, müssen Sie sicherstellen, dass Sie eine neue Liste erstellen, an jeder position. Ein Weg dazu ist es
wird neu zu bewerten
[1]*4
jedes mal statt, bewerten Sie es einmal und machen 3 Referenzen 1 Liste.Fragen Sie sich vielleicht, warum
*
kann nicht machen, unabhängige Objekte, die den Weg der list comprehension funktioniert. Das ist, weil die Multiplikation operator*
arbeitet auf Objekten, ohne zu sehen, Ausdrücken. Wenn Sie*
zu multiplizieren[[1] * 4]
mit 3*
sieht nur das 1-element-Liste[[1] * 4]
ausgewertet, nicht die[[1] * 4
expression-text.*
hat keine Ahnung, wie, um Kopien des Elements, keine Ahnung, wie das zu bewerten[[1] * 4]
, und keine Ahnung, Sie wollen sogar kopiert, und im Allgemeinen, könnte es nicht auch ein Weg sein, um das element kopieren.Nur die option
*
hat, ist zu machen, neue Hinweise auf die existierenden Teilliste, anstatt zu versuchen, um neue Teillisten. Alles andere wäre inkonsistent oder umfangreiche Neugestaltung der grundlegenden Sprache von design-Entscheidungen.Im Gegensatz dazu eine Liste Verständnis greift das element Ausdruck auf jeder iteration.
[[1] * 4 for n in range(3)]
greift[1] * 4
jedes mal aus dem gleichen Grund[x**2 for x in range(3)]
greiftx**2
jeder Zeit. Jede Bewertung von[1] * 4
erzeugt eine neue Liste, also die Liste Verständnis hat, was Sie wollte.Übrigens
[1] * 4
auch nicht kopieren Sie die Elemente der[1]
, aber das spielt keine Rolle, da ganze zahlen sind unveränderlich. Können Sie nicht etwas tun, wie1.value = 2
und drehen Sie eine 1 in eine 2.Ich bin überrascht, dass keine Stelle weist darauf hin, dass, hier ist die Antwort irreführend.
[x]*3
store 3 Verweise wie[x, x, x]
ist nur Recht, wennx
ist veränderlich. Dies bedeutet nicht Arbeit für z.B.a=[4]*3
, wo nacha[0]=5
,a=[5,4,4].
Technisch, es ist immer noch richtig.
[4]*3
ist im wesentlichen äquivalent zux = 4; [x, x, x]
. Es ist wahr, obwohl, dass dies nie dazu führen, alle problem seit4
unveränderlich ist. Auch Ihre anderen Beispiel ist das nicht wirklich ein anderer Fall.a = [x]*3; a[0] = 5
wird nicht zu Problemen führen, auch wennx
ist veränderlich, da bist du nicht ändernx
nur änderna
. Ich würde nicht beschreiben, meine Antwort als irreführend oder falsch ist, Sie eben nicht selbst ins Knie Schießen wenn man sich mit immutable Objekte.sind Sie falsch. Tun
x = 1000; lst = [x]*2; lst[0] is lst[1]
->True
. Python unterscheidet nicht zwischen mutable und immutable Objekte hier zu löschen.ctypes; ctypes.cast(id(1), ctypes.ZEIGER(ctypes.c_int))[6] = 2, aber bereiten Sie für seltsam Verhalten oder einen segmentation Fault.
InformationsquelleAutor CAdaker
Live Python Tutor Visualisieren
Also, warum, wenn wir schreiben die matrix= [[x] * 2] nicht 2 elemnts für das gleiche Objekt wie das Beispiel, das Sie beschreiben, es scheint das gleiche Konzept, was bin ich?
In der Tat, es macht eine Liste mit zwei Elementen, die genau die gleiche Objekt, das
x
verweist. Wenn Sie eine Global eindeutige Objekt mitx = object()
und dann machenmatrix = [[x] * 2]
diese kommt, wie wahr:matrix[0][0] is matrix[0][1]
warum die änderung in der matrix[0] hat keine Auswirkungen auf matrix[1] wie im Beispiel oben mit 2d-matrix.
Überraschung kommen, wenn Sie eine "Kopie" von mutable sequence (in unserem Beispiel ist es ein
list
) also, wenn einrow = [x] * 2
als einmatrix = [row] * 2
wo die beiden Zeilen genau das gleiche Objekt, und ändert sich jetzt in eine Zeilematrix[0][0] = y
plötzlich wider in die andere(matrix[0][0] is matrix[1][0]) == True
InformationsquelleAutor nadrimajstor
Eigentlich ist dies genau das, was Sie erwarten würde. Wir zerlegen das, was hier geschieht:
Schreiben Sie
Dies ist äquivalent zu:
Dies bedeutet
lst
ist eine Liste mit 3 Elementen alle auflst1
. Dies bedeutet, dass die beiden folgenden Zeilen sind gleichwertig:Als
lst[0]
ist nichts, aberlst1
.Erhalten Sie das gewünschte Verhalten, können Sie mit list comprehension:
In diesem Fall wird der Ausdruck neu ausgewertet, für jedes n, was zu einer anderen Liste.
id(lst[0][0])
undid(lst[1][0])
oder sogarid(lst[0])
undid(lst[1])
InformationsquelleAutor PierreBdR
oder auch:
Erstellt eine Liste, die auf die interne
[1,1,1,1]
3 - mal- nicht drei Kopien der inneren Liste, so dass jedes mal, wenn Sie ändern Sie die Liste (in jeder position), werden Sie die Veränderung sehen, die drei mal.Ist es das gleiche wie dieses Beispiel:
wo es wahrscheinlich etwas weniger überraschend.
InformationsquelleAutor Blair Conrad
Neben der akzeptierten Antwort, das erklärt das problem korrekt, in Ihrer Liste Verständnis, wenn Sie mit python-2.x verwenden Sie
xrange()
, liefert einen generator, der effizienter ist (range()
in python 3 hat den gleichen job)_
statt der Wegwerf-variablen
:Auch, als viel mehr Pythonic Weise, die Sie verwenden können,
itertools.wiederholen()
zu erstellen, die ein iterator-Objekt der wiederholten Elemente :P. S. Mit numpy, wenn Sie nur wollen, erstellen Sie ein array von Einsen oder Nullen, die Sie verwenden können
np.ones
undnp.zeros
und/oder für die andere Rufnummer verwendennp.repeat()
:InformationsquelleAutor Kasrâmvd
In einfachen Worten, das ist passiert, weil in python funktioniert alles durch Verweis, so dass, wenn Sie erstellen eine Liste von Liste, so dass Sie im Grunde am Ende mit solchen Problemen.
Um Ihr Problem zu lösen können Sie entweder eine von Ihnen:
1. Verwenden numpy-array Dokumentation für numpy.leer
2. Hängen Sie die Liste, wie Sie eine Liste.
3. Sie können auch das Wörterbuch benutzen, wenn Sie möchten,
InformationsquelleAutor Neeraj Komuravalli
Python-Container enthalten Referenzen auf andere Objekte. Siehe dieses Beispiel:
In diesem
b
ist eine Liste, die enthält ein Element, das eine Referenz auf Listea
. Die Listea
ist veränderlich.Der Multiplikation einer Liste mit einem integer-äquivalent ist, um das hinzufügen der Liste, die sich mehrmals (siehe gemeinsame Sequenz von Operationen). So, weiter mit dem Beispiel:
Können wir sehen, dass die Liste
c
enthält jetzt zwei Verweise auf Listea
entsprichtc = b * 2
.Python-FAQ enthält auch die Erklärung für dieses Verhalten: Wie erstelle ich eine mehrdimensionale Liste?
InformationsquelleAutor Zbyněk Winkler
myList = [[1]*4] * 3
erzeugt ein list-Objekt[1,1,1,1]
im Speicher und kopiert seine Referenz 3 mal über. Dies entsprichtobj = [1,1,1,1]; myList = [obj]*3
. Jede änderungobj
werden reflektiert an drei Orten, woobj
wird in der Liste.Die richtige Aussage wäre:
oder
Wichtige Sache zu beachten hier ist, dass
*
Betreiber ist meist verwendet, um eine Liste von literalen. Da1
ist ein literal, alsoobj =[1]*4
erstellen[1,1,1,1]
wo jeder1
ist Atom-und nicht eine Referenz1
wiederholt 4 mal. Dies bedeutet, dass, wenn wir tunobj[2]=42
, dannobj
wird[1,1,42,1]
nichtals einige vielleicht vermuten.[42,42,42,42]
obj[2] = 42
ersetzt den Verweis auf der index2
im Gegensatz zu mutierenden das Objekt verweist, das index -, das ist, wasmyList[2][0] = ...
tut (myList[2]
ist eine Liste, und die Zuweisung ändert sich die Referenz mit dem index 0 in tha Liste). Natürlich, ganze zahlen sind nicht veränderbar, aber viele Objekt-Typen . Und beachten Sie, dass die[....]
Liste anzeigen notation ist auch eine form von literal-syntax! Nicht zu verwechseln mit der Verbindung (wie Listen) und Skalare Objekte (z.B. ganze zahlen), mit mutable vs. immutable Objekte.InformationsquelleAutor jerrymouse
Lassen Sie uns ändern Sie Ihren code in der folgenden Weise:
Dann mit dieser, führen Sie den folgenden code, um alles weitere klar. Was der code macht im Grunde drucken Sie die
id
s der erhaltenen Objekte, dieund wird uns helfen, zu identifizieren und zu analysieren, was passiert:
Und Sie erhalten die folgende Ausgabe:
So, jetzt lassen Sie uns gehen Sie Schritt-für-Schritt. Sie haben
x
die1
, und ein einzelnes element der Listey
mitx
. Ihr Erster Schritt isty * 4
die erhalten Sie eine neue Listez
ist, das im Grunde[x, x, x, x]
auf, d.h. es erstellt eine neue Liste, die 4 Elemente, die Verweise auf die erstenx
Objekt. Die net-step ist ziemlich ähnlich. Sie im Grunde tunz * 3
, die[[x, x, x, x]] * 3
und zurück[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
aus dem gleichen Grund wie für den ersten Schritt.id
tut, bevor Sie werfen Sie diesen code in Menschen.danke, erledigt 🙂
InformationsquelleAutor bagrat
Ich Schätze, jeder zu erklären, was passiert ist.
Ich schlage vor, einen Weg, es zu lösen:
myList = [[1 for i in range(4)] for j in range(3)]
print myList
Und dann haben Sie:
InformationsquelleAutor awulll
Versuchen, es zu erklären, mehr deskriptiv,
Betrieb 1:
Betrieb 2:
Aufgefallen, warum nicht ändern Sie das erste element der ersten Liste nicht ändern, das zweite element von jeder Liste? Das ist, weil
[0] * 2
ist wirklich eine Liste von zwei zahlen, und eine Referenz auf 0 kann nicht geändert werden.Wenn Sie möchten, erstellen, Klonen, Kopien, versuchen Sie die Operation 3:
eine weitere interessante Möglichkeit zum erstellen von Klonen, Kopien, Operation 4:
InformationsquelleAutor Adil Abbasi
Mithilfe der eingebauten Funktion "Liste" können Sie dies so tun
a.insert(0,[5,1,1,1])
InformationsquelleAutor anand tripathi