1. 程式人生 > 實用技巧 >python深淺拷貝的深度解析(記憶體/地址)

python深淺拷貝的深度解析(記憶體/地址)

前置知識
1.python沒有指標, 可以通過內建函式id來檢視記憶體地址
2.python中list存放的是地址, 而非元素本身, 地址是按順序存放的
3.python容器型別list有兩種地址, 一個是外層物件/父物件地址, 一個是每個元素/子物件的地址
4.當修改list中的不可變物件時, list存放的地址會發生變化, 這點可以保證任何拷貝都無需拷貝不可變物件, 只需要拷貝地址即可

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

# 測試
assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
assert id(a) != id(c) and id(a[0]) == id(c[0]) and id(a[2]) == id(c[2])
assert id(a) != id(d) and id(a[0]) == id(d[0]) and id(a[2]) != id(d[2])

a[0] = 5

assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
assert id(a) != id(c) and id(a[0]) != id(c[0]) and id(a[2]) == id(c[2])
assert id(a) != id(d) and id(a[0]) != id(d[0]) and id(a[2]) != id(d[2])

a[2].append(6)

assert id(a) == id(b) and id(a[0]) == id(b[0]) and id(a[2]) == id(b[2])
assert id(a) != id(c) and id(a[0]) != id(c[0]) and id(a[2]) == id(c[2])
assert id(a) != id(d) and id(a[0]) != id(d[0]) and id(a[2]) != id(d[2])

這三種"拷貝"方式有各自的含義
1.b = a
b是a的一個引用, 不存在任何物件和地址拷貝, 即b只是a的一個別名
2.c = a.copy()
c拷貝了a的外層物件, 內層物件的地址
當a中的不可變物件發生變化, a中的地址變化(參照前置知識4), c中的地址不變, 體現為c中的元素不跟隨a變化
當a中的可變物件發生變化, a中的地址不變, c中的地址不變, 體現為c中的元素跟隨a變化
3.d = copy.deepcopy(a)
d拷貝了a的外層物件, 內層可變物件, 內層不可變物件的地址(參照前置知識4), 與a完全獨立,

總結: 深淺拷貝的區別在於拷貝的是內層物件的地址還是內層物件本身(對於不可變物件來說, 永遠只需要拷貝地址)

如有疏忽錯誤,
歡迎批評指正!