Python3 中淺拷貝 與 深拷貝 理解

Python3 中淺拷貝 與 深拷貝 理解

我的gitee鏈接:
00.Python/Chapter03.DataContainers.md · wan230114/PythonNote - 碼雲 - 開源中國
https://gitee.com/wan230114/PythonNote/blob/master/00.Python/Chapter03.DataContainers.md

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

淺拷貝 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. 原理理解

圖解:

  1. 創建L列表
    創建3個數據對象1, (2, 3), [4, 5],並將其綁定於數據容器對應位置
      L[0]  L[1]           L[2]     # 索引(變量)綁定關係
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
  1. 對L淺拷貝綁定X
    最外層可變數據容器重新在內存中另一區域開闢創建, 而內一層所有數據對象, 只是複製了之前的“數據對象”與“變量”的引用綁定關係到當前數據容器,
    因而改變最外層新拷貝對象對原始對象無影響,而改變拷貝後的數據對象如X[2],將會使L[2]也同時發生改變
    如下圖:
      L[0]  L[1]           L[2]
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
       |     |             |    |     |    |     # 2)內部所有對象正常賦值綁定
    [                                          ] # 1)重新創建最外層可變數據容器
X = [                                          ] # 綁定原始對象關係
      X[0]  X[1]           X[2]     
  1. 對L深拷貝綁定Y
    可以簡單理解爲所有的數據對象全部在內存中拷貝一份,重新指定綁定關係。
    因而,深拷貝後的數據無論如何操作都將不會影響到之前的數據對象,即改變拷貝後的數據對象如Y[2],不會影響L[2]同時發生改變
    (不過深拷貝的實際情況爲了節省計算機資源,只是複製和重新綁定了新的可變數據對象,而其中不可變的數據對象依然保留,重新賦值綁定,這樣節省內存資源的同時亦達到了完全拷貝的同樣效果。)
      L[0]  L[1]           L[2]
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
       |     |    |        |    |    |     |      # 2)其餘不可變對象正常賦值綁定
    [                    [                    ]]  # 1)重新創建所有可變數據容器
Y = [                    [                    ]]  # 綁定新對象關係
      Y[0]  Y[1]           Y[2]     

注:不論嵌套多少層可變對象,它們最終都會重新複製創建

示例:(驗證)

import copy

# 1) L列表的創建
L = [-10,   (-20, -30),   [-40, (-60, -70)]]
Lid = [id(L[0]), id(L[1]), id(L[1][0]), id(L[1][0]), id(L[2][0]), id(L[2][1])]

# 2) 淺拷貝
X = L[:]
Xid = [id(X[0]), id(X[1]), id(X[1][0]), id(X[1][0]), id(X[2][0]), id(X[2][1])]
# 4種淺拷貝方式,效果等價
# X = L[:]
# X = L[::]
# X = L.copy()
# X = copy.copy(L)

# 3) 深拷貝
Y = copy.deepcopy(L)
Yid = [id(Y[0]), id(Y[1]), id(Y[1][0]), id(Y[1][0]), id(Y[2][0]), id(Y[2][1])]

# 對於不可變數據對象的id
print("不可變對象的id", Lid)
print("不可變對象的id", Xid)
print("不可變對象的id", Yid)

# 對於可變數據對象的id
print('原  始', id(L[2]))
print('淺拷貝', id(X[2]))
print('深拷貝', id(Y[2]))

# 改變可變對象
print("L", L)
L[2].append(None)
print('L', L)
print('X', X)  # 綁定的數據對象也被改變
print('Y', Y)  # 可變數據對象已被複制,無影響

"""
不可變對象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896]
不可變對象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896] 
不可變對象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896] 
原  始 1785105256008
淺拷貝 1785105256008
深拷貝 1785105345224
L [-10, (-20, -30), [-40, (-60, -70)]]
L [-10, (-20, -30), [-40, (-60, -70), None]]
X [-10, (-20, -30), [-40, (-60, -70), None]]
Y [-10, (-20, -30), [-40, (-60, -70)]]
"""

練習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: 深拷貝,所有可變對象不受影響"""
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章