Python中的深淺拷貝
在講深淺拷貝之前,想先講一下 is 和 == 的區別,
在進行物件是否相等比較的時候我們可以用 is 和 ==
很多人學習python,不知道從何學起,
很多人學習python,掌握了基本語法過后,不知道在哪里尋找案例上手,
很多已經做案例的人,卻不知道如何去學習更加高深的知識,
那么針對這三類人,我給大家提供一個好的學習平臺,免費領取視頻教程,電子書籍,以及課程的源代碼!
QQ群:961562169
- is: 比較兩個物件的參考是否相同,即 它們的id 是否一樣
- == : 比較兩個物件的值是否相同,
id() ,是Python的一個內置函式,回傳物件的唯一標識,用于獲取物件的記憶體地址,
如下
a = 1
b = 1
print(id(a)) # 2057422768
print(id(b)) # 2057422768
print(a is b) # True
首先,會為整數1分配一個記憶體空間, 變數a 和 b 都指向了這個記憶體空間(記憶體地址相等),所以他們的id相等,
即 a is b 為 True
但是,真的所有整數數字都這樣嗎? 答案是:不是! 只有在 -25 ~ 256范圍中的整數才不會重新分配記憶體空間,
如下所示:
因為257 超出了范圍,所以id不相同,所以 a is b 回傳的值為False,
>>> a = 257
>>> b = 257
>>> print(id(a))
20004752
>>> print(id(b))
20001312
>>> print(a is b)
False
>>> print(a == b)
True
這樣做是考慮到性能,Python對-5 到 256 的整數維護了一個陣列,相當于一個快取, 當數值在這個范圍內,直接就從陣列中回傳相對應的參考地址了,如果不在這個范圍內,會重新開辟一個新的記憶體空間,
is 和 == 哪個效率高?
相比之下, is 比較的效率更高,因為它只需要判斷兩個物件的id是否相同即可,
而 == 則需要多載__eq__ 這個函式,遍歷變數中的所有元素內容,逐次比較是否相同,因此效率較低
淺拷貝 深拷貝
簡單的了解了 is , == , 下面我們一起來看看Python中的深淺拷貝,
先說結論吧:
- 淺拷貝: 拷貝的是物件的參考,如果原物件改變,相應的拷貝物件也會發生改變
- 深拷貝: 拷貝物件中的每個元素,拷貝物件和原有物件不在有關系,兩個是獨立的物件
淺拷貝
a = [1, 2, 3]
b = list(a) # 可以通過list 對串列進行淺拷貝
c = a.copy() # 也可以通過copy函式進行拷貝
# 淺拷貝后,a/b/c的id 各不相同,說明指向了不同的記憶體地址-- 即 生成了新的物件
print(id(a)) # 16301992
print(b, "id:", id(b)) # id:16562024
print(c, "id:", id(c)) # id:16561960
print(a == b) # True 值相同 回傳True
print(a is b) # False id不同所以 is比較回傳False
# 給串列a 添加元素4
a.append(4)
print(a) # [1, 2, 3, 4]
print(b, c) # [1, 2, 3] [1, 2, 3] b和c 不受影響
以上可以看出,淺拷貝會分配一個新的記憶體空間,創建一個新的物件,但是如果被拷貝物件中有可變物件會怎么樣呢? 看下面的代碼
a = [1, 2, [3, 4]]
b = a.copy()
print(id(a)) # 23967528
print(id(b)) # 21738984
# 改變a中的可變物件
a[-1].append(5)
print(a)
# 在給a新增元素6
a.append(6)
# [1, 2, [3, 4, 5], 6]
print(a)
# [1, 2, [3, 4, 5]]
print(b)
可以看出,在串列a中新增的元素6,并沒有影響b,但是在a的嵌套串列中新增的元素5,卻影響了元素b,
原因在于: 對于a和b都指向了同一個串列[3, 4], 所以當a中在串列新增元素5的時候,改變了那個串列的值,b也指向了那個串列,所以也會發生改變,
再看看下面的代碼
a = [1, 2, (3, 4)]
b = a.copy()
print(id(a)) # 59162536
print(id(b)) # 60143400
# 改變a中的可變物件
a[-1] += (5, )
# [1, 2, (3, 4, 5)]
print(a)
# [1, 2, (3, 4)]
print(b)
對于元組(3, 4),因為元組不可變,所以在元組中新增了元素5,實際上是生成了新的元組物件,而b串列中的元組參考并沒有發生改變,
通過上面的兩個例子可以看出淺拷貝可能會帶來的弊端,在使用中需要大家進行相應的判斷,或者去完整的拷貝某個物件,即 深拷貝,
深拷貝
所謂深拷貝呢,就是重新分配一個記憶體空間(新物件),將原物件中的所有元素通過遞回的方式進行拷貝到新物件中,
在Python中 通過 copy.deepcopy() 來實作深拷貝,
import copy
a = [1, 2, (3, 4)]
# 深拷貝
b = copy.deepcopy(a)
# 因為生成了新的物件所以,回傳False
print(a is b)
a[-1] += (5,)
a.append(6)
print(a) # [1, 2, (3, 4, 5), 6]
print(b) # [1, 2, (3, 4)] 深拷貝后的物件,根本不受原物件的任何影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/107554.html
標籤:其他
