在python中,由於共享內存導致copy有深copy和淺copy之分,大家稍有不注意就可能會改變不希望被改變的信息。
淺copy
數據“半共享”
- 可以淺copy的數據類型:list、dict、set
Q:何爲淺copy?
A:只能copy最淺層(即第一層),不能copy數據類型中嵌套的數據類型
在python 中 id()
方法可以查看存放變量的內存地址,這爲我們下面理解深淺copy提供了便利。
不多說,上碼:
>>> a = [1,[23,4],3]
>>> a
[1, [23, 4], 3]
>>> b = a.copy()
>>> b
[1, [23, 4], 3]
>>> b[0]=2
>>> b
[2, [23, 4], 3]
>>> a
[1, [23, 4], 3]
>>> b[1][1]=234234 #更改列表中嵌套的二級列表
>>> b
[2, [23, 234234], 3]
>>> a #原列表也會被更改
[1, [23, 234234], 3]
>>> id(a)
2198613584328
>>> id(b)
2198613596744
>>> id(a[0])
140710427074960
>>> id(b[0])
140710427074992 #對於改變的元素,地址也會變
>>> id(b[1])
2198613584904 #b中嵌套的二級列表地址
>>> id(a[1])
2198613584904 #原列表中嵌套的二級列表地址,可看出和copy的地址一致
>>> id(a[2])
140710427075024
>>> id(b[2])
140710427075024 #對於沒有改變的元素,地址與原列表地址一致
從代碼可以看出:改變b中嵌套的二級列表會影響a中的二級列表。
Q:爲什麼二級列表裏的數值被更改了?
A:淺copy時,內存會開闢一個新的空間存放一個新的列表,列表中的元素和元素地址都會被copy過來,但可變數據類型(二級列表)被當做一個整體不被copy,所以二級列表的地址也和原列表的地址保持一致,即對二級列表中的元素更改時,a和b會相互影響,元素永遠相同。
而一級列表中的不可變數據類型,雖然元素與地址都被複制過來,但兩者進行修改時不會相互影響,並且修改後地址會變得不一致。而在一級列表添加新的元素時,兩者同樣不會相互影響,只要不改變copy過來的元素,地址會一直與copy過來的一致。
dict和set也是如此。
深copy
copy所有內容。深copy後改變其內容不會對原數據產生任何影響。
深copy需要導入python自帶的庫——copy。
上碼:
>>> import copy
>>> a = [1,[23,4],3]
>>> b = copy.deepcopy(a)
>>> b
[1, [23, 4], 3]
>>> b[0] = 2
>>> b
[2, [23, 4], 3]
>>> a
[1, [23, 4], 3]
>>> b[1][1] = 234234
>>> b
[2, [23, 234234], 3]
>>> a
[1, [23, 4], 3]
>>> id(a)
2198613756168
>>> id(b)
2198613785864
>>> id(a[0])
140710427074960
>>> id(b[0])
140710427074992 #對於改變的元素,地址會改變
>>> id(a[1])
2198613756744 #原列表中嵌套的二級列表地址
>>> id(b[1])
2198613785288 #b中嵌套的二級列表地址,可看出和原列表中嵌套的二級列表地址不一致
>>> id(a[2])
140710427075024
>>> id(b[2])
140710427075024 #對於沒有改變的元素,地址與原列表地址一致
從代碼可以看出:a,b互不影響。
淺析深淺copy
深copy是拷貝所有內容。包括內部(二級列表)的所有,形成一個新的對象,雖然與之前的值和內容一模一樣,但是它們時完完全全的兩個對象,二級列表的地址同樣被拿出來存在新的內存當中,地址同樣會不一樣,所以做出改變時不會相互影響;其它與淺copy一致,不可變數據類型改變時不會相互影響,且改變後地址會發生改變。