切換語言為:簡體
深入理解 Python 中的深複製和淺複製

深入理解 Python 中的深複製和淺複製

  • 爱糖宝
  • 2024-08-27
  • 2058
  • 0
  • 0

在編寫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

深入理解 Python 中的深複製和淺複製

淺複製

複製是指將當前物件重新複製一份,在跟變數進行繫結。

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]

深入理解 Python 中的深複製和淺複製

此時我們可以看出來,物件是被重新制作了一份,然後在跟變數進行繫結的,這個時候,我們更改某個變數的時候,另外一個變數指向的物件是不受任何影響的。
但是,如果當我們的物件中存在其他物件時,可能會出現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,這就是由於淺複製導致的。
淺複製複製的只是最外層物件,內部物件仍然是引用的

深入理解 Python 中的深複製和淺複製

透過[:],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]

深入理解 Python 中的深複製和淺複製

深複製與淺複製的優勢分析

  1. 記憶體分析

可以透過分析得到,淺複製更加節省記憶體,因為沒必要構建出所有的新的一份物件

2.安全性

深複製更加安全,因為每個物件都是獨一份的,在修改任意變數的時候,不必擔心會不會影響到其他的變數

3.當物件不可變時

假設一個物件中,存在其他物件,但是其他物件都是不可變的,這個時候,不推薦使用深複製,這是因為不可變物件無法新增或刪除元素,可以保障不會出現某個變數改變時,對其他變數的改變,同時,淺複製可以節省很大一部分記憶體

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.