iamlaosong文
曾經看到這樣一個問題,一個字典中的元素是列表,將這個列表元素賦值給一個變量,然后修改這個列表中元素的值,結果發現,字典中那個列表也同樣修改了。
那個問題如下:
dict = {'a':[1,2,3,4,5],'b':2} x = dict['a'] for i in range(5): x[i] = 0 print(dict['a']) 程序運行結果如下:
[0, 0, 0, 0, 0]
這兒涉及到Python賦值到底是引用還是拷貝一份的問題,即賦值時是傳值還是傳址。上面問題是將“a”的值賦給了x出現了上述情況,如果是將“b”的值賦給了x,當我們修改x的值時,字典dict的值并不受影響。
>>> dict = {'a':[1,2,3,4,5],'b':2} >>> x = dict['b'] >>> x 2 >>> x=x+3 >>> x 5 >>> dict {'a': [1, 2, 3, 4, 5], 'b': 2} >>> 那么問題來了,變量賦值傳遞時什么情況下是傳值(拷貝),什么情況下是傳址(引用)呢?
1、直接拷貝
當我們不知道是引用還是拷貝的情況下,可以顯式的拷貝。比如字典對象本身都具有拷貝的方法:
x=dict.copy()
沒有拷貝方法的對象,也是可以拷貝的。這兒我們引入一個深拷貝的概念,深拷貝——即python的copy模塊提供的一個deepcopy方法。深拷貝會完全復制原變量相關的所有數據,在內存中生成一套完全一樣的內容,在這個過程中我們對這兩個變量中的一個進行任意修改都不會影響其他變量。還是上面的代碼,如果改成如下:
import copy dict = {'a':[1,2,3,4,5],'b':2} x = copy.deepcopy(dict['a']) for i in range(5): x[i] = 0 print(dict['a']) 運行結果dict值不受影響。
除了深拷貝,copy模塊還提供一個copy方法,稱其為淺拷貝,對于簡單的對象,深淺拷貝都是一樣的,上面的詞典對象的copy方法就是淺拷貝。
>>> dict{'a': [8, 2, 3, 4, 5], 'b': 4}>>> dd=copy.copy(dict)>>> dd{'a': [8, 2, 3, 4, 5], 'b': 4}>>> dd['a'][0]=7>>> dd{'a': [7, 2, 3, 4, 5], 'b': 4}>>> dict{'a': [7, 2, 3, 4, 5], 'b': 4}>>> ee=dict.copy()>>> ee{'a': [7, 2, 3, 4, 5], 'b': 4}>>> ee['a'][0]=9>>> ee{'a': [9, 2, 3, 4, 5], 'b': 4}>>> dict{'a': [9, 2, 3, 4, 5], 'b': 4}>>> ee['b']=5>>> ee{'a': [9, 2, 3, 4, 5], 'b': 5}>>> dict{'a': [9, 2, 3, 4, 5], 'b': 4}>>> 淺拷貝時改變第一層次相互不受影響(上例中詞典b值的修改),第二層次(上例中詞典a的列表值修改)就相互影響了,改一個,其他跟著變。看看id吧:
>>> id(dict) 20109472 >>> id(dd) 20244496 >>> id(ee) 20495072 >>> id(dd['a']) 20272112 >>> id(ee['a']) 20272112 >>> id(dict['a']) 20272112 >>>
新聞熱點
疑難解答