從底層分析python中深拷貝和淺拷貝區別
深淺拷貝在python中經常使用,其區別的外在表現是:
使用淺拷貝,當原容器物件中可變物件中有元素髮生變化,拷貝得到的物件也會變化。而使用深拷貝時,不會有這種問題。
聽起來有一點難理解,看例子比較直觀:
淺拷貝
>>> list1 = [['a', 'b'], 1, 2]
>>> list3 = copy.copy(list1)
>>> list3
[['a', 'b'], 1, 2]
>>> list1[0][0] = 'c' #修改lsit1
>>> list3
[['c', 'b'], 1, 2] #list3也變了
深拷貝
>>> list1 = [['a', 'b'], 1, 2]
>>> list3 = copy.deepcopy(list1)
>>> list1[0][0] = 'c' #修改list1
>>> list3
[['a', 'b'], 1, 2] #list3沒有變
但是為什麼會這樣,可以由下圖解釋:
當我們宣告list1 = [['a', 'b'], 1, 2]時,計算機做了這些事:
1、在記憶體中開闢一段空間,用來存放字元a,b和數字1,數字2
2、在記憶體開闢一段空間,用來存放一個列表,我們稱為list2。list2中存放兩個指標,分別指向字元a和b
3、在記憶體開闢一段空間,用來存放一個列表lsit1,list1中存放三個指標,分別指向list2,數字1和數字2
當執行淺拷貝lsit3 = copy.copy(list1)時,計算機開闢一段記憶體給list3,list3儲存三個指標,分別指向list2,數字1和數字2。當執行list1[0][0] = 'c'時,list2物件修改了,而list3的第一個指標指向list2,所以我們看到list3的第一個元素也變了。
當執行深拷貝lsit4 = copy.copy(list1)時,計算機開闢一段記憶體給list4,和淺拷貝不同的是,計算機同時開闢一段空間給新的列表,我們稱為lsit5。list5中儲存2個指標,分別指向字元a和b。
同時list4儲存三個指標,分別指向list5,數字1和數字2。此時,當執行list1[0][0] = 'c'時,list2物件修改了,但list4的第一個指標指向list5,list5並沒有修改,所以list4沒有改變。
總結:深拷貝會把可變物件也拷貝一份,而淺拷貝不會。
上面例子中說的是列表(可變物件)的拷貝,那對於元組,字元等不可不物件呢?
答案是,對不可不物件,其實不存在深淺拷貝的問題。無論怎麼拷貝,效果都是新建立一個指向不可變物件的指標而已。
>>> a = 'f'
>>> b = copy.copy(a)
>>> id(a)
4302389968
>>> id(b)
4302389968
>>> c = copy.deepcopy(a)
>>> id(c)
4302389968
>>>
>>> d = a
>>> id(a)
4302389968