在編寫Python程式碼的時候,我們經常在兩個變數間透過=
號進行連結,這樣的好處是兩個變數都可以使用某些內容。例如下面這段程式碼:
old = [1, 2, 3, 4, 5] new = old print("new:", new) print("old:", old)
這樣一來,我們得到了兩個包含[1, 2, 3, 4, 5]
的列表,且不論是透過old
變數還是透過new
變數,我們都可以做到操作這個列表,首先,用=
號的操作不能稱為複製,而是賦值
,它只是將一個變數透過另一個變數繫結在某個物件上。這個時候,透過任何一個變數改變物件時,另外一個變數也一定會改變。
old = [1, 2, 3, 4, 5] new = old print("new:", new) print("old:", old) old.append(6) print("new:", new) print("old:", old)
new: [1, 2, 3, 4, 5] old: [1, 2, 3, 4, 5] new: [1, 2, 3, 4, 5, 6] old: [1, 2, 3, 4, 5, 6]
1. 在記憶體空間中開闢出一塊記憶體空間,該空間儲存[1, 2, 3, 4, 5]這樣的一個列表物件(簡稱物件A) 2. 將變數old與物件A透過一條連線進行繫結(這樣我們就可以根據連線,透過old變數找到物件A) 3. 透過old變數找到物件A,然後將變數new透過一條連線實現與物件A的繫結 4. 透過old變數找到物件A,在物件A中新增一個元素6
淺複製
複製
是指將當前物件重新複製一份,在跟變數進行繫結。
old = [1, 2, 3, 4, 5] new = old[:] print("new:", new) print("old:", old) old.append(6) print("new:", new) print("old:", old)
new: [1, 2, 3, 4, 5] old: [1, 2, 3, 4, 5] new: [1, 2, 3, 4, 5] old: [1, 2, 3, 4, 5, 6]
此時我們可以看出來,物件是被重新制作了一份,然後在跟變數進行繫結的,這個時候,我們更改某個變數的時候,另外一個變數指向的物件
是不受任何影響的。
但是,如果當我們的物件中存在其他物件時,可能會出現BUG。
old = [1, 2, 3, [4, 5, 6], 7, 8] new = old[:] old.append(9) old[3].append(10) print("new:", new) print("old:", old)
new: [1, 2, 3, [4, 5, 6, 10], 7, 8] old: [1, 2, 3, [4, 5, 6, 10], 7, 8, 9]
可以看到,new
指向的物件中並沒有9這個數字,但是卻存在10,這就是由於淺複製
導致的。
淺複製複製的只是最外層物件,內部物件仍然是引用的。
透過[:]
,copy.copy
,for迴圈
,列表生成式
實現的複製都是淺複製。
深複製
透過迭代的方式,將所有的物件都進行一份複製
,透過copy.deepcopy
實現。
import copy old = [1, 2, 3, [4, 5, 6], 7, 8] new = copy.deepcopy(old) old.append(9) old[3].append(10) print("new:", new) print("old:", old)
new: [1, 2, 3, [4, 5, 6], 7, 8] old: [1, 2, 3, [4, 5, 6, 10], 7, 8, 9]
深複製與淺複製的優勢分析
記憶體分析
可以透過分析得到,淺複製更加節省記憶體,因為沒必要構建出所有的新的一份物件
2.安全性
深複製更加安全,因為每個物件都是獨一份的,在修改任意變數的時候,不必擔心會不會影響到其他的變數
3.當物件不可變時
假設一個物件中,存在其他物件,但是其他物件都是不可變的,這個時候,不推薦使用深複製,這是因為不可變物件無法新增或刪除元素,可以保障不會出現某個變數改變時,對其他變數的改變,同時,淺複製可以節省很大一部分記憶體