1. 程式人生 > >[隨筆重寫] Python3 的深拷貝與淺拷貝

[隨筆重寫] Python3 的深拷貝與淺拷貝

發生 deep 同步 所有 副本 拷貝 python .py 不可變

1. Python3 關於深淺拷貝的官方文檔

  • 文檔地址:Python3.7.2
  • 源碼地址:lib/copy.py

2. 先說結論

  • 深拷貝與淺拷貝是對復合對象而言的
  • 深拷貝會構造一個新的復合對象,然後遞歸地將在原始對象中所有元素的副本對應地寫入新復合對象中
  • 淺拷貝會構造一個新的復合對象,然後(在允許的前提下)向其中寫入對原始對象的引用

3. 開始分析

  • 復合對象:包含其他對象的對象,如列表、類實例等
  • 模塊、方法、堆棧跟蹤、堆棧幀、文件、套接字、窗口、數組等不能被拷貝
  • 示例
# 例1

import copy                         # 導入 copy 模塊

list1_1 = [0, 1, 2, [‘a‘, ‘b‘]]
list1_2 = list1_1                   # 賦值
list1_3 = list1_1.copy()            # 淺拷貝;同 list1_3 = list1_1[:]
list1_4 = copy.copy(list1_1)        # 淺拷貝
list1_5 = copy.deepcopy(list1_1)    # 深拷貝

# 打印出拷貝後的 list1_1 ~ list1_5
print("list1_1 =", list1_1)
print("list1_2 =", list1_2)
print("list1_3 =", list1_3)
print("list1_4 =", list1_4)
print("list1_5 =", list1_5)
print(‘-‘*40)                       # 分割線

list1_1.append(4)                   # 在 list1_1 末尾添加一個元素 4
list1_1[3].append(‘c‘)              # 向 list1_1 中內嵌的列表末尾添加一個元素 ‘c‘

# 打印出更改後的 list1_1 ~ list1_5
print("list1_1‘ =", list1_1)
print("list1_2‘ =", list1_2)
print("list1_3‘ =", list1_3)
print("list1_4‘ =", list1_4)
print("list1_5‘ =", list1_5)

>>>

list1_1 = [0, 1, 2, [‘a‘, ‘b‘]]
list1_2 = [0, 1, 2, [‘a‘, ‘b‘]]
list1_3 = [0, 1, 2, [‘a‘, ‘b‘]]
list1_4 = [0, 1, 2, [‘a‘, ‘b‘]]
list1_5 = [0, 1, 2, [‘a‘, ‘b‘]]
----------------------------------------
list1_1‘ = [0, 1, 2, [‘a‘, ‘b‘, ‘c‘], 4]
list1_2‘ = [0, 1, 2, [‘a‘, ‘b‘, ‘c‘], 4]
list1_3‘ = [0, 1, 2, [‘a‘, ‘b‘, ‘c‘]]
list1_4‘ = [0, 1, 2, [‘a‘, ‘b‘, ‘c‘]]
list1_5‘ = [0, 1, 2, [‘a‘, ‘b‘]]


  • 由例1 可看出
    1. 簡單的賦值只是將引用傳給新對象,新舊對象除變量名外毫無區別
    2. 原對象中非第一層的可變元素發生變化時,淺拷貝的新對象中的對應元素同步變化
    3. 深拷貝的新對象是一個真正的副本,不隨原對象的改變而改變
  • 補充
    1. 拷貝後的新對象占用新的空間,但其內部的元素指向原對象內部對應元素的地址
    2. 原對象中非第一層的不可變元素重新生成時,淺拷貝的新對象中的對應元素保持不變

[隨筆重寫] Python3 的深拷貝與淺拷貝