2013-07-25 68 views
4

我明白,當你做一個字典的淺拷貝時,你實際上會製作一個引用的副本。所以如果我這樣做:淺拷貝:爲什麼列表更改但不是字符串?

x={'key':['a','b','c']} 
y=x.copy() 

所以列表['a','b','c']的參考被複制到y中。無論何時我更改列表(例如x['key'].remove('a')),xict和y都會改變。這部分我明白。但是,當我考慮這樣的情況如下:

x={'user':'admin','key':['a','b','c']} 
y=x.copy() 

當我做y['user']='guest',X [「用戶」]不會改變,但在列表中仍然共享相同的參考。 所以我的問題是什麼使字符串不同於列表?這背後的機制是什麼?

回答

14

你正在做兩件不同的事情。當你做

x['key'].remove('a') 

你突變x['key']引用的對象。如果另一個變量引用同一個對象,你會看到從這個角度來看的變化,太:

Pythontutor visualization Pythontutor visualization 2

然而,在第二種情況下,情況就不同了:

PT vis 3

如果你

y['user']='guest' 

rebindy['user']到一個新的對象。這當然不會影響x['user']或它引用的對象。順便說一下,這與可變與不可變對象無關。如果你沒有

x['key'] = [1,2,3] 

你也不會改變y['key']之一:

PT vis 4

看到它交互方式PythonTutor.com

+0

對於一些很好的補充閱讀,多解包一下,請參閱[關於Python名稱和值的事實和神話](http://nedbatchelder.com/text/names.html)。 –

+0

所以如果我把y ['user']當作一個指針,它包含的地址讓我們說Ox0001指向字符串'admin'的地址,但是當我做y ['user'] ='guest'時,python將爲字符串'guest'分配一個新的「內存塊」Ox0002,並將y ['user']內的地址更新爲新地址0x0002? – jujae

+0

@jujae:這是關於發生的事情,是的。 –

5

區別在於,在一次的情況下,您正在爲字典鍵指定一個新值,而在另一種情況下,您正在修改現有值。注意到其中的差別在你的兩段代碼:

x['key'].remove('a') 

這裏沒有=跡象。你沒有在詞典中分配任何東西。事實上,字典幾乎不能「知道」發生了什麼。您只需進入並操縱字典中的對象。

y['user'] = 'guest' 

這裏你實際上是給字典鍵賦一個新的值。

在第二種情況下,您無法執行remove的等效操作,因爲字符串是不可變的。但是,區別不是「因爲字符串是不可變的」。區別在於你的的變異列表而不是字符串。您可以通過執行

x['key'] = ['new', 'list'] 

這將在x分配一個新值鍵時,會在第一種情況下第二個例子中的行爲,留下y不受影響。

+0

非常感謝,你的回答和Tim Pietzcker的一切都讓我很清楚。 – jujae