一文詳細(xì)了解python的深淺拷貝

深淺拷貝是什么:在Python中,理解深拷貝(deep copy)和淺拷貝(shallow copy)對于處理復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如列表、字典或自定義對象,是非常重要的。這兩種拷貝方式?jīng)Q定了數(shù)據(jù)在內(nèi)存中的復(fù)制方式,進(jìn)而影響程序的運(yùn)行結(jié)果
淺拷貝:
1.淺拷貝的定義:
淺拷貝是一種復(fù)制操作,它創(chuàng)建一個新對象,并將原對象的內(nèi)容復(fù)制到新對象中。對于原對象內(nèi)部的子對象,淺拷貝不會遞歸地復(fù)制它們,而是直接引用這些子對象。因此,淺拷貝后的對象和原對象共享內(nèi)部的子對象。
2.淺拷貝的實(shí)現(xiàn)方式
(1)使用copy模塊的copy()函數(shù)
import copy original_list = [1, 2, [3, 4]] shallow_copied_list = copy.copy(original_list)
(2)使用列表、字典等數(shù)據(jù)結(jié)構(gòu)的工廠函數(shù)
original_list = [1, 2, [3, 4]] shallow_copied_list = list(original_list) # 列表的工廠函數(shù)
(3)使用切片操作(適用于列表)
original_list = [1, 2, [3, 4]] shallow_copied_list = original_list[:] # 切片操作
(4)使用字典的copy()方法
original_dict = {'a': 1, 'b': [2, 3]}
shallow_copied_dict = original_dict.copy() # 字典的 copy() 方法3.淺拷貝的特點(diǎn)
新對象,舊引用:淺拷貝會創(chuàng)建一個新對象,但對象內(nèi)部的子對象仍然是原對象中子對象的引用。
共享子對象:如果原對象包含可變子對象(如列表、字典等),修改這些子對象會影響淺拷貝后的對象。
性能較高:由于淺拷貝不會遞歸復(fù)制子對象,因此它的性能比深拷貝更高。
4.淺拷貝的示例
示例 1:修改淺拷貝后的對象
import copy
original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list)
# 修改淺拷貝后的對象
shallow_copied_list[0] = 100
shallow_copied_list[2][0] = 300
print("Original List:", original_list)
print("Shallow Copied List:", shallow_copied_list)輸出
Original List: [1, 2, [300, 4]]
Shallow Copied List: [100, 2, [300, 4]]
解釋:
修改
shallow_copied_list[0]不會影響original_list,因?yàn)檫@是對新對象本身的修改。修改
shallow_copied_list[2][0]會影響original_list,因?yàn)閮?nèi)部的子列表是共享的。
示例 2:使用切片操作實(shí)現(xiàn)淺拷貝
original_list = [1, 2, [3, 4]]
shallow_copied_list = original_list[:]
# 修改淺拷貝后的對象
shallow_copied_list[0] = 100
shallow_copied_list[2][0] = 300
print("Original List:", original_list)
print("Shallow Copied List:", shallow_copied_list)輸出
Original List: [1, 2, [300, 4]]
Shallow Copied List: [100, 2, [300, 4]]
示例 3:字典的淺拷貝
original_dict = {'a': 1, 'b': [2, 3]}
shallow_copied_dict = original_dict.copy()
# 修改淺拷貝后的字典
shallow_copied_dict['a'] = 100
shallow_copied_dict['b'][0] = 200
print("Original Dict:", original_dict)
print("Shallow Copied Dict:", shallow_copied_dict)輸出
Original Dict: {'a': 1, 'b': [200, 3]}
Shallow Copied Dict: {'a': 100, 'b': [200, 3]}
解釋:
修改
shallow_copied_dict['a']不會影響original_dict,因?yàn)檫@是對新對象本身的修改。修改
shallow_copied_dict['b'][0]會影響original_dict,因?yàn)閮?nèi)部的列表是共享的。
5.淺拷貝的適用場景
淺拷貝適用于以下場景:
對象內(nèi)部沒有嵌套的可變對象:如果對象內(nèi)部只包含不可變對象(如整數(shù)、字符串、元組等),淺拷貝是安全的。
性能要求較高:淺拷貝的性能比深拷貝更高,因?yàn)樗粫f歸復(fù)制子對象。
- 共享子對象是期望的行為:如果你希望拷貝后的對象和原對象共享某些子對象,淺拷貝是一個合適的選擇。
6.淺拷貝的注意事項(xiàng)
共享子對象的風(fēng)險:如果原對象包含可變子對象,修改這些子對象會影響淺拷貝后的對象。如果不希望共享子對象,應(yīng)該使用深拷貝。
不可變對象的特殊性:對于不可變對象(如整數(shù)、字符串、元組等),淺拷貝和深拷貝的行為是相同的,因?yàn)椴豢勺儗ο蟛荒鼙恍薷摹?/p>
深拷貝:
深拷貝(Deep Copy)是Python中一種遞歸復(fù)制對象的方式,它會創(chuàng)建一個新對象,并遞歸地復(fù)制原對象內(nèi)部的所有子對象。這意味著深拷貝后的對象與原對象完全獨(dú)立,修改其中一個不會影響另一個。深拷貝適用于需要完全獨(dú)立副本的場景,尤其是當(dāng)對象內(nèi)部包含嵌套的可變對象時。
1.深拷貝的定義
深拷貝是一種遞歸復(fù)制操作,它創(chuàng)建一個新對象,并遞歸地復(fù)制原對象內(nèi)部的所有子對象。深拷貝后的對象與原對象完全獨(dú)立,即使原對象包含嵌套的可變對象(如列表、字典等),修改其中一個對象也不會影響另一個。
2.深拷貝的實(shí)現(xiàn)方式
在Python中,可以通過 copy 模塊的 deepcopy() 函數(shù)實(shí)現(xiàn)深拷貝。
使用copy.deepcopy()函數(shù)
3.深拷貝的特點(diǎn)
完全獨(dú)立:深拷貝后的對象與原對象完全獨(dú)立,修改其中一個不會影響另一個。
遞歸復(fù)制:深拷貝會遞歸地復(fù)制對象內(nèi)部的所有子對象,包括嵌套的可變對象。
- 性能較低:由于深拷貝需要遞歸復(fù)制所有子對象,因此它的性能比淺拷貝低,尤其是在處理大型或復(fù)雜的嵌套結(jié)構(gòu)時。
4.深拷貝的示例
通過以下示例,可以更好地理解深拷貝的行為。
示例 1:修改深拷貝后的對象
輸出:
Original List: [1, 2, [3, 4]] Deep Copied List: [100, 2, [300, 4]]
解釋:
修改
deep_copied_list[0]不會影響original_list,因?yàn)檫@是對新對象本身的修改。修改
deep_copied_list[2][0]也不會影響original_list,因?yàn)樯羁截愡f歸復(fù)制了內(nèi)部的子列表,兩個列表是完全獨(dú)立的。
示例 2:嵌套字典的深拷貝
輸出:
Original Dict: {'name': 'Alice', 'details': {'age': 25, 'hobbies': ['reading', 'traveling']}}
Deep Copied Dict: {'name': 'Alice', 'details': {'age': 30, 'hobbies': ['reading', 'traveling', 'cooking']}}解釋:
修改
deep_copied_dict中的嵌套字典和列表不會影響original_dict,因?yàn)樯羁截愡f歸復(fù)制了所有子對象。
示例 3:自定義對象的深拷貝
輸出

解釋:
修改 person2 的 name 和 friends 不會影響 person1,因?yàn)樯羁截愡f歸復(fù)制了所有屬性。
5.深拷貝的適用場景
深拷貝適用于以下場景:
需要完全獨(dú)立的副本:當(dāng)對象內(nèi)部包含嵌套的可變對象時,深拷貝可以確保副本與原對象完全獨(dú)立。
復(fù)雜的數(shù)據(jù)結(jié)構(gòu):如嵌套的列表、字典、自定義對象等。
- 避免副作用:在函數(shù)中傳遞復(fù)雜對象時,深拷貝可以避免意外修改原對象。
6.深拷貝的注意事項(xiàng)
性能開銷:深拷貝需要遞歸復(fù)制所有子對象,因此在處理大型或復(fù)雜的嵌套結(jié)構(gòu)時,性能開銷較大。
- 循環(huán)引用問題:如果對象之間存在循環(huán)引用(如對象A引用對象B,對象B又引用對象A),深拷貝可能會導(dǎo)致棧溢出或無限遞歸。Python的
copy.deepcopy()函數(shù)已經(jīng)處理了循環(huán)引用問題,但在自定義深拷貝邏輯時需要注意。
7.深拷貝的實(shí)現(xiàn)原理
Python的 copy.deepcopy() 函數(shù)通過遞歸遍歷對象的所有屬性來實(shí)現(xiàn)深拷貝。它會維護(hù)一個備忘錄(memo)來記錄已經(jīng)復(fù)制的對象,從而避免循環(huán)引用導(dǎo)致的無限遞歸。
深淺拷貝的實(shí)際應(yīng)用:
深淺拷貝在實(shí)際編程中有廣泛的應(yīng)用,尤其是在處理復(fù)雜數(shù)據(jù)結(jié)構(gòu)或需要確保數(shù)據(jù)獨(dú)立性時。以下是一些常見的應(yīng)用場景和示例,幫助你更好地理解它們的實(shí)際用途。
1.數(shù)據(jù)處理與修改
在處理數(shù)據(jù)時,尤其是嵌套的數(shù)據(jù)結(jié)構(gòu)(如列表嵌套列表、字典嵌套字典等),你可能需要在不影響原始數(shù)據(jù)的情況下對數(shù)據(jù)進(jìn)行修改或分析。這時,深拷貝非常有用。
import copy
# 原始數(shù)據(jù)
original_data = {
'name': 'Alice',
'scores': [90, 85, 88],
'details': {'age': 25, 'city': 'New York'}
}
# 深拷貝數(shù)據(jù)
copied_data = copy.deepcopy(original_data)
# 修改拷貝后的數(shù)據(jù)
copied_data['scores'][0] = 95
copied_data['details']['city'] = 'San Francisco'
# 原始數(shù)據(jù)不受影響
print("Original Data:", original_data)
print("Copied Data:", copied_data)應(yīng)用場景:
數(shù)據(jù)備份與恢復(fù)。
- 數(shù)據(jù)預(yù)處理(如修改數(shù)據(jù)后用于機(jī)器學(xué)習(xí)模型訓(xùn)練,而不影響原始數(shù)據(jù))。
2.配置管理
在程序中,配置通常以字典或嵌套字典的形式存儲。如果你需要基于某個默認(rèn)配置生成多個獨(dú)立的配置,深拷貝可以確保每個配置之間互不干擾。
import copy
# 默認(rèn)配置
default_config = {
'debug': False,
'database': {
'host': 'localhost',
'port': 3306
}
}
# 創(chuàng)建多個獨(dú)立配置
config_1 = copy.deepcopy(default_config)
config_2 = copy.deepcopy(default_config)
# 修改配置
config_1['database']['host'] = '192.168.1.1'
config_2['debug'] = True
print("Config 1:", config_1)
print("Config 2:", config_2)應(yīng)用場景:
多環(huán)境配置(開發(fā)、測試、生產(chǎn))。
- 動態(tài)生成多個獨(dú)立的配置。
3.對象復(fù)制與狀態(tài)管理
在面向?qū)ο缶幊讨?,對象可能包含嵌套的對象或?fù)雜的狀態(tài)。如果你需要復(fù)制一個對象并確保新對象的狀態(tài)獨(dú)立于原對象,深拷貝是必要的。
import copy
class Player:
def __init__(self, name, level):
self.name = name
self.level = level
self.inventory = []
def add_item(self, item):
self.inventory.append(item)
# 創(chuàng)建玩家對象
player1 = Player("Alice", 10)
player1.add_item("Sword")
player1.add_item("Shield")
# 深拷貝玩家對象
player2 = copy.deepcopy(player1)
# 修改拷貝后的對象
player2.name = "Bob"
player2.add_item("Bow")
# 查看兩個對象的狀態(tài)
print(f"Player 1: {player1.name}, {player1.inventory}")
print(f"Player 2: {player2.name}, {player2.inventory}")應(yīng)用場景:
游戲開發(fā)中復(fù)制角色或物品。
- 狀態(tài)快照與恢復(fù)(如撤銷操作)。
4. 避免副作用
def process_data(data):
# 淺拷貝數(shù)據(jù)以避免修改原始數(shù)據(jù)
data_copy = data.copy()
data_copy.append("Processed")
return data_copy
original_data = [1, 2, 3]
result = process_data(original_data)
print("Original Data:", original_data)
print("Result:", result)應(yīng)用場景:
函數(shù)式編程中避免副作用。
數(shù)據(jù)處理管道中確保數(shù)據(jù)獨(dú)立性。
深拷貝:適用于需要完全獨(dú)立副本的場景,如數(shù)據(jù)處理、配置管理、對象復(fù)制等。
淺拷貝:適用于性能敏感的場景,或者當(dāng)對象內(nèi)部沒有嵌套結(jié)構(gòu)時。
建議 選擇使用深拷貝還是淺拷貝取決于具體的需求和數(shù)據(jù)結(jié)構(gòu)。如果你不確定,深拷貝通常是更安全的選擇,盡管它可能會帶來一些性能開銷。
總結(jié)
到此這篇關(guān)于python深淺拷貝的文章就介紹到這了,更多相關(guān)python深淺拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python面向?qū)ο笕腴T教程之從代碼復(fù)用開始(一)
這篇文章主要給大家介紹了關(guān)于python面向?qū)ο笕腴T教程之從代碼復(fù)用開始的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價值,需要的朋友們來一起看看吧2018-12-12
如何使用Django默認(rèn)的Auth權(quán)限管理系統(tǒng)
本文主要介紹了如何使用Django默認(rèn)的Auth權(quán)限管理系統(tǒng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02

