Python中的淺拷貝和深拷貝

我的原書鏈接:點擊傳送

3.6.3. 淺拷貝 與 深拷貝 理解

(淺層複製 與 深層複製 理解)

淺拷貝 shallow copy
深拷貝 deep copy

總結:

淺拷貝: 是指在複製過程中,只複製一層變量綁定關係,不會複製深層變量綁定的對象的複製過程
深拷貝: 對所有可變對象進行層層複製,實現對象的各自獨立。

3.6.3.1. 語法及使用方法:

基本語法:

import copy   # 導入copy模塊
L = "任意類型數據"
L2 = copy.copy(L)     # 淺拷貝
L2 = copy.deepcopy(L) # 深拷貝

特別的,在列表中還可以通過切片和自身的copy方法進行淺層複製,如下:

# 淺拷貝
# 1) 利用切片方法。切片——返回切片後的新對象。如
L2 = L[:]
L2 = L[::]
# 2) 利用列表自身方法
L2 = L.copy()

3.6.3.2. 原理理解

淺層複製只複製最外一層的數據或容器對象,內部直接被賦值綁定於新對象對應位置

示例:如何解釋Out4和Out5相同,Out9和Out10部分相同,以及後面的測試結果?

In [1]: import copy

In [2]: L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]


# 淺拷貝測試
In [3]: X = L.copy()

In [4]: [id(x) for x in L]
Out[4]: [1684750713584, 1684750470920, 1684749580488]

In [5]: [id(x) for x in X]
Out[5]: [1684750713584, 1684750470920, 1684749580488]

In [6]: id(L), id(X)
Out[6]: (1684750584648, 1684750627144)


# 深拷貝測試
In [7]: Y = copy.deepcopy(L)

In [8]: [id(x) for x in L]
Out[8]: [1684750713584, 1684750470920, 1684749580488]

In [9]: [id(x) for x in X]
Out[9]: [1684750713584, 1684750470920, 1684749580488]

In [10]: [id(x) for x in Y]
Out[10]: [1684750713584, 1684750470920, 1684748555272]


# 數據測試
In [11]: L.append("測試1")

In [12]: L[2].append("測試2")

In [13]: L, X, Y
Out[13]: 
([-10, (-20, -30), [-40, -50, (-60, -70), '測試2'], '測試1'],
 [-10, (-20, -30), [-40, -50, (-60, -70), '測試2']],
 [-10, (-20, -30), [-40, -50, (-60, -70)]])

圖解:

  1. 創建L列表
    創建3個數據對象,放入列表中(綁定於數據容器對應位置)
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]

綁定關係如下:

# 索引(變量)綁定關係,索引也可看做特殊變量
      L[0]  L[1]           L[2]
       |     |             |
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
  1. 對L淺拷貝綁定X
X = L.copy()
# 或
X = L[::]
# 或 其他...

綁定關係如下:

      L[0]  L[1]           L[2]
        |     |            |
        |     |            |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
        |     |            |
        |     |            |
      X[0]  X[1]           X[2]     
        |     |            |
        |     |            |
X = [                                          ]
# 1)重新創建最外層可變數據容器,淺拷貝創建新的最外層對象
# 2)內部所有對象正常賦值綁定
# 綁定原始對象關係,3個數據對象同時被L[N]和L[X]綁定

最外層可變數據容器重新在內存中另一區域開闢創建, 而內一層所有數據對象, 都只是在原來的基礎上簡單賦值,因而改變最外層新拷貝對象對原始對象無影響,而改變拷貝後的數據對象如X[2],將會使L[2]也同時發生改變

  1. 對L深拷貝綁定Y
    可以簡單理解爲所有的數據對象全部在內存中拷貝一份,並重新對新數據對象指定綁定關係。
    因而,深拷貝後的數據無論如何操作都將不會影響到之前的數據對象,即改變拷貝後的數據對象如Y[2],不會影響L[2]同時發生改變
    (不過深拷貝的實際情況爲了節省計算機資源,只是複製和重新綁定了新的可變數據對象,而其中不可變的數據對象依然保留,重新賦值綁定,這樣節省內存資源的同時亦達到了完全拷貝的同樣效果。)

練習

練習1:

import copy  # 導入複製模塊
L = [3.1, 3.2]
L1 = [1, 2, L]
L2 = copy.deepcopy(L1)  # 實現深拷貝
L[0] = 3.14
print(L1)  # _________
print(L2)  # _________

# [1, 2, [3.14, 3.2]] #此列表由於淺拷貝受影響
# [1, 2, [3.1, 3.2]] #此列表不受影響

練習2:

import copy

a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')

print(a)  # _________
print(b)  # _________
print(c)  # _________
print(d)  # _________

# [1, 2, 3, 4, ['a', 'b', 'c'], 5]  
# [1, 2, 3, 4, ['a', 'b', 'c'], 5]  
# [1, 2, 3, 4, ['a', 'b', 'c']]     
# [1, 2, 3, 4, ['a', 'b']]
"""解析: 
> a: a加了5,a[4]加了'c'  
> b: 賦值綁定操作,與a完全一致  
> c: 淺拷貝了最外層可變對象,最外層不受影響,但內部可變對象受影響  
> d: 深拷貝,所有可變對象不受影響"""
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章