2010-12-15 57 views
1

我正在從一個csv文件中讀取行的py腳本,操縱它們,並將它們放回。到目前爲止,我有csv列表轉換工作。爲什麼python中的'for'循環改變未引用的列表?

我遇到的問題是當我迭代臨時列表時,for循環會更改所有臨時列表,而不僅僅是我想要的那個。這是我想說的一個簡單的例子。

>>> 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']] 

所以上面是直截了當的(希望)。 (讓我們假設除了複製列表之外,我還想做其他事情,只是爲了保持簡單)。

但現在這裏是我沒有得到的部分。

>>> 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']] 

當我要修改的子列表第一部分,並將其保存到一個新的列表「Z」,它會修改列表T中的!

這是怎麼回事? z,y和t指向相同的內存位置?

而且,這裏發生了什麼?:

>>> 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']] 

對上述問題類似,爲什麼y及t得到改變?

在此先感謝!

回答

4

你的三個列表是不同的,但只有他們兩個人之間共享的元素:

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

如果is運營商告訴你,你引用指向同一個對象,然後改到物體會出現不你使用哪個參考。

爲了避免這種情況,如果你想要的元素的副本使用copy模塊:

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

對於列表的淺表副本,您可以使用'y [:]' – SingleNegationElimination 2010-12-15 23:34:28

+0

謝謝jleedev!雖然[:]回答並解決了我的問題,您的copy.deepcopy解決方案也是如此,這是我在腳本中必須做的事情,因爲淺拷貝是不夠的(顯然)。你解決了我的問題! :) – RaytheonLiszt 2010-12-15 23:49:44

+0

@Raytheon'[:]'slice,一個簡單的'for'循環和一個淺拷貝都具有完全相同的效果。 – 2010-12-15 23:54:19

7

Python什麼也沒有引用。 row是對ly內的實際元素的引用。突變row突變該元素,並將其添加到另一個對象添加原始元素。

+4

使用'row [:]'複製'row'。 – katrielalex 2010-12-15 23:11:25

+0

@katrielalex:我可以讓你喜歡100次嗎?我遇到了列表引用的OP問題,並且無法爲我的生活弄清楚如何複製列表而不是複製引用。是否所有列表片返回一個副本,而不是像這樣的引用? – DGH 2010-12-15 23:28:25

+1

@DGH:對於'list',是的。儘管淺拷貝。 – 2010-12-15 23:29:18

0

「?是Z,Y和T指向同一個內存位置」不是,但是z [0],y [0]和t [0]是(雖然不稱它爲內存位置,但這不是C)。您將同一個清單['hi', 'ho']追加到z,y和t。所以它是一樣的列表。如果你不希望它是同一個列表,你必須首先製作一個副本。