深淺copy
前言:深淺copy會在很多面試題中都會問到,所以搞懂它們之間的區別是很有必要性的
本篇中的所有圖解只是幫助大家進行理解
1. 可變與不可變數據類型
- 可變數據類型:列表,字典,集合
- 不可變數據類型:字符串,元組,數字
2. 淺拷貝
先拿圖說話:圖中的123123等數值假設爲內存地址
在圖中我們可以明顯的看到淺拷貝過後,兩個列表l1和l2的引用還是指的是同一個值,所以當我們更改這兩個列表的任何可變數據類型時,另一個列表的值一定會跟着變化。
注意:這裏我強調了更改的值必須是可變數據類型時,另一個列表的值纔會跟着變化
代碼證明:
- 更改嵌套列表的值
l1 = [1, '小明', [1, '小紅', 3]] l2 = l1.copy() # 或者導入copy模塊,l2 = copy.copy(l1) l1[-1][1] = '李華' print(id(l1)) print(id(l2)) print(id(l1[-1])) print(id(l2[-1])) print(l1) print(l2) # 輸出: 400648025856 # 兩個列表的內存地址不同代表另外給l2開闢一塊新的空間 400648025984 117588479680 # 證明兩個列表中的可變數據類型爲同一個 117588479680 [1, '小明', [1, '李華', 3]] # 對l1的嵌套列表進行了更改,l2也跟着變化,代表了兩個列表引用的值是同一個 [1, '小明', [1, '李華', 3]]
- 更改列表中不可變數據類型的值
這時肯定就有人疑惑了,不是說兩個列表都是引用的同一個值麼,爲什麼l1的值更改了,而l2的值沒有更改呢?原因是這樣的,我們其實更改的值不是真實存儲的值,而且更改了l1列表中內存地址爲456456的引用,將456456指向了另一個值 ‘小張’,主要原因就是字符串它是不可變的數據類型,所以我們更改不了字符串的值。l1 = [1, '小明', [1, '小紅', 3]] l2 = l1.copy() l1[1] = '小張' print(l1) print(l2) 輸出: [1, '小張', [1, '小紅', 3]] # 兩個列表的值竟然不一樣了 [1, '小明', [1, '小紅', 3]]
總結:根據以上實驗,我們可以這樣理解,淺拷貝就是兩個列表中的可變數據類型仍是同一個。更改任何一個列表中的可變數據,另一個列表的值也會跟着變化
3. 深拷貝
和字面意思一樣,完全複製一份新的出來,與原列表再無任何聯繫。這裏就不再畫圖。
我們首先得藉助內置的copy模塊
-
更改嵌套的可變數據類型,這裏我們以字典進行演練。注意與列表一樣也是可變數據類型。
import copy l1 = [1, '小明', {'name': '小張'}] l2 = copy.deepcopy(l1) l1[-1]['name'] = '小花' print(id(l1)) print(id(l2)) print(l1) print(l2) # 輸出: 705449836608 # 兩個列表的內存地址仍不一樣,代表爲拷貝的l2新開闢了一塊空間 705449810432 [1, '小明', {'name': '小花'}] # 更改了l1中的可變數據類型字典的值,l1變化了,而l2沒有變化 [1, '小明', {'name': '小張'}]
這就證明了深拷貝後的列表已經與原先的列表無關了。
-
補充:上面我們說的深拷貝後的列表與原列表沒有任何聯繫了,其實並不然,python解釋器做了優化的,兩個列表中的不可變數據類型指向仍爲同一個值,但是可變數據類型就是各自的互不影響。
4. 思考
此時是深copy還是淺copy
l1 = [1, 2, '小紅', {'name': '夏天'}]
l2 = l1[:]
l1[-1]['name'] = '冬天'
print(l1)
print(l2)
答案是:淺拷貝
結語:深拷貝與淺拷貝在面試時會問,所以還是得分清兩者之間的區別,本章知識點到這裏結束。覺得博主講的還算不錯的可以點個贊,你們的鼓勵是我最大的動力。