Python中copy()?函數(shù)淺拷貝與深拷貝示例詳解
前言
在 Python 編程中,對象的拷貝(復(fù)制) 是一個常見又容易被忽視的概念。很多初學(xué)者在使用 copy() 時,常常會遇到修改一個對象導(dǎo)致另一個對象也被改變的“奇怪現(xiàn)象”。本文將深入理解 Python 的 copy() 函數(shù)、淺拷貝與深拷貝的區(qū)別,并通過示例讓你徹底搞清楚它們的原理。
一、為什么需要拷貝對象?
當(dāng)你在 Python 中使用賦值語句時,例如:
a = [1, 2, 3] b = a
此時,a 和 b指向同一個對象。這意味著修改 b 也會影響 a:
b.append(4) print(a) # 輸出:[1, 2, 3, 4] print(b) # 輸出:[1, 2, 3, 4]

這往往不是我們想要的結(jié)果。
如果希望創(chuàng)建一個“新的對象”,而不是僅僅復(fù)制引用,這時就需要用到 拷貝函數(shù)。
二、copy模塊簡介
Python 標(biāo)準(zhǔn)庫提供了一個專門用于復(fù)制對象的模塊:copy。
該模塊中有兩個重要函數(shù):
copy.copy(x)—— 執(zhí)行 淺拷貝copy.deepcopy(x)—— 執(zhí)行 深拷貝
我們先來看看淺拷貝。
三、淺拷貝 (copy.copy())
淺拷貝會創(chuàng)建一個新的對象,但不會遞歸地復(fù)制內(nèi)部的可變對象。
示例:
import copy list_a = [1, [2, 3], 4] list_b = copy.copy(list_a) print(list_a == list_b) # True,內(nèi)容相同 print(list_a is list_b) # False,指向不同對象
修改外層列表時,互不影響:
list_b.append(5) print(list_a) # [1, [2, 3], 4] print(list_b) # [1, [2, 3], 4, 5]
但修改內(nèi)部的可變對象時,淺拷貝仍然會“聯(lián)動”:
list_b[1].append(99) print(list_a) # [1, [2, 3, 99], 4] print(list_b) # [1, [2, 3, 99], 4, 5]
? 結(jié)論:淺拷貝只復(fù)制最外層容器,內(nèi)部元素仍然是原對象的引用。
四、深拷貝 (copy.deepcopy())
深拷貝則會遞歸地復(fù)制所有對象,生成完全獨(dú)立的一份副本。
import copy list_a = [1, [2, 3], 4] list_b = copy.deepcopy(list_a) list_b[1].append(99) print(list_a) # [1, [2, 3], 4] print(list_b) # [1, [2, 3, 99], 4]
? 結(jié)論:深拷貝創(chuàng)建了一個完全獨(dú)立的對象副本,任何修改都不會相互影響。
五、不同數(shù)據(jù)類型的拷貝行為
| 數(shù)據(jù)類型 | 淺拷貝結(jié)果 | 深拷貝結(jié)果 |
|---|---|---|
int, float, str, bool | 不可變對象,直接共享 | 相同效果 |
list, dict, set | 復(fù)制容器,但內(nèi)部引用相同 | 完全獨(dú)立副本 |
tuple | 如果內(nèi)部包含可變對象,淺拷貝仍共享引用 | 內(nèi)部對象獨(dú)立 |
| 自定義類對象 | 可自定義 __copy__ / __deepcopy__ 方法 | 可完全控制復(fù)制邏輯 |
六、自定義類的拷貝行為
Python 允許開發(fā)者通過實(shí)現(xiàn)特殊方法 __copy__ 和 __deepcopy__ 來控制類的復(fù)制方式。
示例:
import copy
class Person:
def __init__(self, name, hobbies):
self.name = name
self.hobbies = hobbies
def __copy__(self):
print("調(diào)用淺拷貝")
return type(self)(self.name, self.hobbies)
def __deepcopy__(self, memo):
print("調(diào)用深拷貝")
new_person = type(self)(self.name, copy.deepcopy(self.hobbies, memo))
return new_person
p1 = Person("Alice", ["reading", "coding"])
p2 = copy.copy(p1)
p3 = copy.deepcopy(p1)
七、常見坑點(diǎn)總結(jié)
- 淺拷貝不會遞歸復(fù)制內(nèi)部對象
a = [[1, 2], [3, 4]] b = copy.copy(a) b[0].append(99) print(a) # [[1, 2, 99], [3, 4]]
- 不可變對象(如 int, str, tuple)無需擔(dān)心淺拷貝問題
a = (1, 2, 3) b = copy.copy(a) print(a is b) # True
- 深拷貝性能開銷較大
深拷貝會遞歸復(fù)制所有內(nèi)容,對于嵌套層級深或?qū)ο髲?fù)雜的結(jié)構(gòu),速度會明顯變慢。
如果不需要完全隔離,優(yōu)先使用淺拷貝。
八、總結(jié)
| 概念 | 是否創(chuàng)建新對象 | 是否遞歸復(fù)制 | 適用場景 |
|---|---|---|---|
賦值(=) | 否 | 否 | 兩變量共享同一對象 |
淺拷貝(copy.copy()) | 是 | 否 | 僅需復(fù)制一層結(jié)構(gòu) |
深拷貝(copy.deepcopy()) | 是 | 是 | 需要完全獨(dú)立的副本 |
九、實(shí)踐建議
- 若僅修改外層容器,用
copy.copy()即可。 - 若修改嵌套結(jié)構(gòu)(如列表中包含列表),用
copy.deepcopy()。 - 若對象復(fù)雜,考慮自行實(shí)現(xiàn)
__copy__與__deepcopy__,以提升性能與控制力。
? 淺拷貝復(fù)制外殼,深拷貝復(fù)制靈魂。
到此這篇關(guān)于Python中copy() 函數(shù)淺拷貝與深拷貝的文章就介紹到這了,更多相關(guān)Python中copy()函數(shù)淺拷貝深拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Django實(shí)現(xiàn)隨機(jī)圖形驗(yàn)證碼的示例
這篇文章主要介紹了Django實(shí)現(xiàn)隨機(jī)圖形驗(yàn)證碼的示例,幫助大家更好的學(xué)習(xí)和使用django框架,感興趣的朋友可以了解下2020-10-10
Python編程實(shí)現(xiàn)粒子群算法(PSO)詳解
這篇文章主要介紹了Python編程實(shí)現(xiàn)粒子群算法(PSO)詳解,涉及粒子群算法的原理,過程,以及實(shí)現(xiàn)代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
Pytorch損失函數(shù)torch.nn.NLLLoss()的使用
這篇文章主要介紹了Pytorch損失函數(shù)torch.nn.NLLLoss()的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02

