Python面試:淺拷貝與深拷貝的區(qū)別與應用

在 Python 中,淺拷貝和深拷貝是兩種復制對象的方法,它們在處理復雜數(shù)據(jù)結(jié)構(gòu)(如列表、字典、對象等)時的行為不同。讓我們來詳細了解這兩者的區(qū)別以及它們的應用場景。


ctrl_c.png

概念與區(qū)別

淺拷貝(Shallow Copy)

概念:淺拷貝創(chuàng)建一個新對象,但不遞歸復制原對象內(nèi)的子對象。相反,新對象中包含的子對象是對原對象中子對象的引用。因此,原對象和新對象共享相同的子對象。
使用:在 Python 中,使用 copy 模塊中的 copy 函數(shù)進行淺拷貝:

import copy
original_list = [[1, 2, 3], [4, 5, 6]]
shallow_copy = copy.copy(original_list)

行為:淺拷貝后的對象是獨立的對象,但子對象仍然是原對象中的相同引用。這意味著對新對象中的子對象的修改會影響原對象中的相同子對象。
應用場景:在你希望復制對象,但仍然保持對子對象的引用的情況下,可以使用淺拷貝。這在一些需要共享子對象的情況下可能是有用的。

深拷貝(Deep Copy)

概念:深拷貝創(chuàng)建一個新對象,并遞歸復制原對象中的所有子對象。因此,新對象與原對象完全獨立,任何一方的修改都不會影響另一方。
使用:在 Python 中,使用 copy 模塊中的 deepcopy 函數(shù)進行深拷貝:

import copy
original_list = [[1, 2, 3], [4, 5, 6]]
deep_copy = copy.deepcopy(original_list)

行為:深拷貝后的對象與原對象完全獨立。你可以在新對象中自由修改子對象,而不會影響原對象中的子對象。
應用場景:在你希望創(chuàng)建一個完全獨立的對象,而不共享任何子對象的引用的情況下,可以使用深拷貝。這在你希望確保對原對象的獨立性和完整性時非常有用。
總結(jié)
區(qū)別:淺拷貝只復制對象本身,而不復制其內(nèi)部的子對象。深拷貝遞歸復制對象及其內(nèi)部的所有子對象。
應用場景:根據(jù)你的需求選擇使用淺拷貝或深拷貝。如果你希望對象之間共享子對象的引用,可以使用淺拷貝;如果你希望對象完全獨立,可以使用深拷貝。
例如:

import copy

# 示例數(shù)據(jù)
original_list = [[1, 2, 3], [4, 5, 6]]

# 淺拷貝
shallow_copy = copy.copy(original_list)

# 深拷貝
deep_copy = copy.deepcopy(original_list)

# 修改原列表中的子列表
original_list[0].append(99)

print("原列表:", original_list)
print("淺拷貝:", shallow_copy)  # 淺拷貝中的子列表也受影響
print("深拷貝:", deep_copy)  # 深拷貝中的子列表不受影響

在這個例子中,你可以看到對原列表中的子列表的修改會影響淺拷貝,但不會影響深拷貝。

應用場景

淺拷貝

淺拷貝在實際應用中非常有用,特別是在需要復制對象,但不需要完全獨立的對象副本時。下面是一個用常見的學校班級換了數(shù)學老師的例子來展示淺拷貝,展示如何在管理對象引用、共享數(shù)據(jù)結(jié)構(gòu)以及避免不必要的深拷貝時使用淺拷貝。

import copy

math_teacher = {"name": "AAA"}
# 學生模板
student_a = {
    "name": "student_a",
    "math_teacher": math_teacher
}

student_b = copy.copy(student_a)
# 淺拷貝出來的對象修改name屬性是不會影響student_a原對象的
student_b["name"] = "student_b"

print("換老師前", student_a, student_b)
# 學生b知道學校更換老師,學生a也會知道
student_b["math_teacher"]["name"] = "BBB"
print("換老師后", student_a, student_b)

# Outputs
# 換老師前 {'name': 'student_a', 'math_teacher': {'name': 'AAA'}} {'name': 'student_b', 'math_teacher': {'name': 'AAA'}}
# 換老師后 {'name': 'student_a', 'math_teacher': {'name': 'BBB'}} {'name': 'student_b', 'math_teacher': {'name': 'BBB'}}

這里可以看到淺拷貝出來的新對象(student_b),將子對象(math_teacher)老師的名字(name)改成“BBB”后,原對象(student_a)的老師名字也從“AAA”變成了“BBB”,說明了對新對象中的子對象的修改會影響原對象中的相同子對象。這里的不用深拷貝的原因,他們的老師是共享對象,改一個地方就可以了,否則每個深拷貝出來的對象都需要重新把子對象老師的名字給重新賦值一遍,增加操作復雜度。

深拷貝在 Python 中也有許多實際應用場景,特別是在需要復制復雜數(shù)據(jù)結(jié)構(gòu)而不希望子對象之間共享引用的情況下。深拷貝通過遞歸復制對象及其子對象,確保原對象和副本之間完全獨立。

比如某些全局配置是獨一份的且不能隨意修改的,如果淺拷貝后然后要將數(shù)據(jù)結(jié)構(gòu)傳遞給不同的函數(shù)或模塊使用,可能會產(chǎn)生一些意想不到副作用(可能會被函數(shù)/模塊修改了影響全局);又或者是在一些數(shù)據(jù)結(jié)構(gòu)需要備份的時候也會考慮深拷貝。

總結(jié)

淺拷貝和深拷貝是python面試中最常問到的問題,也是可變對象和不可變對象概念的延伸。

  • 對于不可變對象(如Python中的int、float、str、tuple等),深拷貝和淺拷貝的結(jié)果是相同的,因為這些對象本質(zhì)上是不可改變的,并且在淺拷貝時并不會引用其他對象。
  • 對于可變對象(如Python中的list、dict、set等),淺拷貝和深拷貝的行為有很大不同。淺拷貝會導致共享引用,而深拷貝會創(chuàng)建完全獨立的副本。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容