2010-12-15 5 views
1

Ich arbeite an einem Py-Skript, das Zeilen aus einer CSV-Datei einliest, manipuliert und wieder ausgibt. Bisher habe ich die csv um die Konvertierung zu listen.Warum ändert eine for-Schleife in Python nicht referenzierte Listen?

Das Problem, das ich habe, ist, wenn ich über die temporären Listen iteriere, ändern die for-Schleifen alle Temp-Listen, anstatt nur die eine, die ich will. Hier ist ein einfaches Beispiel für das, was ich sagen möchte.

>>> l = [['hi', 'ho'],['no', 'go']] 
>>> t = [] 
>>> y = [] 
>>> 
>>> for row in l: 
...  row[0] = '123' 
...  y.append(row) 
...  t.append(row) 
... 
>>> y 
[['123', 'ho'], ['123', 'go']] 
>>> t 
[['123', 'ho'], ['123', 'go']] 

Also das obige ist einfach (hoffentlich). (Nehmen wir an, ich möchte andere Dinge tun, als nur die Liste zu kopieren. Ich wollte es einfach halten).

Aber jetzt ist hier der Teil, den ich nicht bekomme.

>>> z = [] 
>>> for row in y: 
...  row[0] = 'xxxx' 
...  z.append(row) 
... 
>>> z 
[['xxxx', 'ho'], ['xxxx', 'go']] 
>>> t 
[['xxxx', 'ho'], ['xxxx', 'go']] 
>>> y 
[['xxxx', 'ho'], ['xxxx', 'go']] 

Wenn ich will den ersten Teil in den Unterlisten ändern, und es zu einer neuen Liste ‚z‘ speichern, ändert es die Liste t, wie gut!

Was geht hier vor? Sind z, y und t auf den gleichen Speicherort?

Auch was hier passiert ?:

>>> for rowx in y: 
...  rowx[0] = 'x55x' 
...  z.append(rowx) 
... 
>>> z 
[['xxxx', 'ho'], ['x55x', 'go'], ['x55x', 'go'], ['x55x', 'go']] 
>>> t 
[['xxxx', 'ho'], ['x55x', 'go']] 
>>> y 
[['xxxx', 'ho'], ['x55x', 'go']] 

auf die obige Frage ähnliche, warum y und t geändert zu werden?

Vielen Dank im Voraus!

Antwort

4

Ihre drei Listen sind unterschiedlich, aber es gibt nur zwei Elemente zwischen ihnen geteilt:

>>> y[0] is t[0] is z[0] 
True 
>>> y[1] is t[1] is z[1] 
True 

Wenn der is Operator Sie, dass Ihre Referenzen auf das gleiche Objekt zeigen erzählt, dann auf das Objekt ändert, erscheint kein Egal welche Referenz du benutzt.

Um dies zu vermeiden, verwenden Sie das copy Modul wenn Sie eine Kopie der Elemente wollen:

>>> import copy 
>>> a = copy.deepcopy(y) 
>>> a 
[['xxxx', 'ho'], ['xxxx', 'go']] 
>>> a[0] is y[0] 
False 
>>> a[0][0] = 'copy!' 
>>> y 
[['xxxx', 'ho'], ['xxxx', 'go']] 
+0

Für eine flache Kopie von Listen können Sie 'y [:]' – SingleNegationElimination

+0

Dank jleedev! Während [:] beantwortet und meine Frage gelöst hat, tut das auch Ihre Kopie.deepcopy Lösung, was ich in meinem Skript machen musste, da eine seichte Kopie (anscheinend) nicht genug war. Du hast mein Problem gelöst! :) – RaytheonLiszt

+0

@Raytheon Die '[:]' Scheibe, eine einfache 'for' Schleife und eine seichte Kopie haben alle genau den gleichen Effekt. –

7

Python hat nichts aber Referenzen. row ist eine Referenz auf das tatsächliche Element innerhalb l oder y. Muting row mutiert dieses Element, und das Hinzufügen zu einem anderen Objekt fügt das ursprüngliche Element hinzu.

+4

Verwenden Sie 'row [:]', um eine Kopie von 'row' zu erstellen. – katrielalex

+0

@katrielalex: Kann ich Sie 100 mal upvoten? Ich bin auf das OP-Problem mit Listenverweisen gestoßen und konnte nicht für mein Leben herausfinden, wie man eine Liste kopiert, anstatt die Referenz zu kopieren. Liefern alle Listen-Slices eine Kopie anstelle einer Referenz wie dieser? – DGH

+1

@DGH: Für 'liste', ja. Eine flache Kopie obwohl. –

0

„Sind z, y und t zeigt auf den gleichen Speicherplatz“

Nein, aber z [0], y [0] und t [0] sind (obwohl es nicht Speicherorte genannt werden, ist dies nicht C). Sie fügen dieselbe Liste ['hi', 'ho'] an beide z, y und t an. Es ist also die gleiche Liste. Wenn Sie nicht möchten, dass es dieselbe Liste ist, müssen Sie zuerst eine Kopie erstellen.

Verwandte Themen