最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python深拷貝與淺拷貝的實(shí)現(xiàn)及對比詳解(很多人都理解錯(cuò)了)

 更新時(shí)間:2026年05月08日 09:11:31   作者:zzwq.  
這篇文章主要介紹了Python深拷貝與淺拷貝實(shí)現(xiàn)及對比的相關(guān)資料,淺拷貝適用于你只關(guān)心外部對象的拷貝,不需要完全獨(dú)立的內(nèi)部對象副本時(shí),淺拷貝的性能相對較好,適用于對象結(jié)構(gòu)較簡單或嵌套層級(jí)較淺的情況,需要的朋友可以參考下

前言

在 Python 中,進(jìn)行變量賦值、函數(shù)傳參、數(shù)據(jù)結(jié)構(gòu)復(fù)制等操作時(shí),經(jīng)常會(huì)遇到一個(gè)經(jīng)典問題:淺拷貝(Shallow Copy)與深拷貝(Deep Copy)的區(qū)別。很多初學(xué)者甚至一些有經(jīng)驗(yàn)的開發(fā)者,在面對嵌套結(jié)構(gòu)時(shí),常常因?yàn)槔斫獠簧疃瓤樱瑢?dǎo)致程序出現(xiàn)意想不到的 Bug。

一、從一個(gè)簡單的例子開始

先來看一段代碼,猜猜輸出結(jié)果是什么:

python
original = [1, 2, [3, 4]]
copy1 = original.copy() ? ? ? ? ?# 淺拷貝
copy2 = original[:] ? ? ? ? ? ? ?# 也是淺拷貝

original[2][0] = 99
original[0] = 100

print(original) ? # [100, 2, [99, 4]]
print(copy1) ? ? ?# ???
print(copy2) ? ? ?# ???

如果你以為 copy1 和 copy2 都保持原樣 [1, 2, [3, 4]],就犯了經(jīng)典錯(cuò)誤。實(shí)際應(yīng)該是:

python
print(copy1) ? # [1, 2, [99, 4]]
print(copy2) ? # [1, 2, [99, 4]]

為什么 copy1 的第一個(gè)元素沒變,但內(nèi)部列表卻變了?這就要從淺拷貝的本質(zhì)說起。

二、Python 中的對象與引用

在理解拷貝之前,必須先掌握 Python 中變量與對象的關(guān)系。Python 中,變量名只是對象的一個(gè)標(biāo)簽或引用,實(shí)際的數(shù)據(jù)存儲(chǔ)在內(nèi)存中的對象里。

python
a = [1, 2, 3]
b = a ? ? ? ? ?# b 和 a 引用同一個(gè)對象
b.append(4)
print(a) ? ? ? # [1, 2, 3, 4] ? a 也被修改了

這里 b = a 只是讓 b 指向了 a 所指向的對象,并沒有創(chuàng)建新的對象。這種賦值稱為引用賦值

拷貝則是創(chuàng)建新對象,但根據(jù)復(fù)制深度不同,新對象與原對象的關(guān)系也不同。

三、淺拷貝(Shallow Copy)

1. 什么是淺拷貝

淺拷貝會(huì)創(chuàng)建一個(gè)新的對象,但它只復(fù)制原對象中元素的引用,而不會(huì)遞歸復(fù)制元素本身。換句話說,新對象中的子對象仍然是原對象中子對象的引用。

2. 淺拷貝的實(shí)現(xiàn)方式

Python 中常見的淺拷貝方式:

使用 copy 模塊的 copy() 函數(shù):import copy; new_obj = copy.copy(obj)

  • 對于列表:list.copy() 或 list[:] 或 list(list_obj)
  • 對于字典:dict.copy() 或 dict(dict_obj)
  • 對于集合:set.copy()
python
import copy

lst = [1, 2, [3, 4]]
lst_copy = copy.copy(lst) ? # 淺拷貝
lst_slice = lst[:] ? ? ? ? ? # 也是淺拷貝
lst_construct = list(lst) ? ?# 淺拷貝

print(lst_copy is lst) ? ? ? # False,外層對象不同
print(lst_copy[2] is lst[2]) # True,內(nèi)部列表是同一個(gè)

3. 淺拷貝的行為演示

python
original = [1, 2, [3, 4]]
shallow = original.copy()

original[0] = 100 ? ? ? ?# 修改外層不可變元素(int)
original[2][0] = 99 ? ? ?# 修改內(nèi)部可變列表

print(original) ? # [100, 2, [99, 4]]
print(shallow) ? ?# [1, 2, [99, 4]]

修改 original[0] 時(shí),由于整數(shù)是不可變對象,shallow[0] 仍然指向原來的整數(shù) 1,所以不受影響。
修改 original[2][0] 時(shí),因?yàn)?original[2] 和 shallow[2] 指向的是同一個(gè)列表對象,所以修改會(huì)反映到 shallow 中。

關(guān)鍵點(diǎn):淺拷貝只保證外層容器是新對象,但內(nèi)部的元素依然是原對象的引用。

四、深拷貝(Deep Copy)

1. 什么是深拷貝

深拷貝會(huì)遞歸地復(fù)制原對象中的所有元素,創(chuàng)建一個(gè)完全獨(dú)立的新對象。新對象與原對象沒有任何共享的引用關(guān)系,修改原對象不會(huì)影響新對象,反之亦然。

2. 深拷貝的實(shí)現(xiàn)方式

使用 copy 模塊的 deepcopy() 函數(shù):import copy; new_obj = copy.deepcopy(obj)

python
import copy

lst = [1, 2, [3, 4]]
deep = copy.deepcopy(lst)

print(deep is lst) ? ? ? ?# False
print(deep[2] is lst[2]) ?# False,內(nèi)部列表也被復(fù)制了

3. 深拷貝的行為演示

python
import copy

original = [1, 2, [3, 4]]
deep = copy.deepcopy(original)

original[0] = 100
original[2][0] = 99

print(original) ? # [100, 2, [99, 4]]
print(deep) ? ? ? # [1, 2, [3, 4]] ?完全不受影響

深拷貝實(shí)現(xiàn)了真正的“備份”,無論原對象結(jié)構(gòu)多復(fù)雜,新對象都擁有自己獨(dú)立的數(shù)據(jù)。

五、深入理解:自定義對象的拷貝

1. 自定義類與 __copy__、__deepcopy__

對于自定義對象,copy.copy() 和 copy.deepcopy() 會(huì)調(diào)用對象的 __copy__() 和 __deepcopy__() 方法(如果定義了)。如果沒有定義,則默認(rèn)行為是:copy.copy() 會(huì)創(chuàng)建一個(gè)新實(shí)例,并遞歸復(fù)制所有屬性(淺拷貝)。copy.deepcopy() 會(huì)遞歸復(fù)制所有屬性(深拷貝)。

但我們可以通過自定義這些方法來控制復(fù)制行為。

python
import copy

class MyClass:
? ? def __init__(self, data):
? ? ? ? self.data = data

? ? def __copy__(self):
? ? ? ? # 自定義淺拷貝行為
? ? ? ? new_instance = type(self)(self.data[:]) ? # 假設(shè) data 是列表
? ? ? ? return new_instance

? ? def __deepcopy__(self, memo):
? ? ? ? # 自定義深拷貝行為
? ? ? ? new_instance = type(self)(copy.deepcopy(self.data, memo))
? ? ? ? return new_instance

2. 不可變對象的特殊情況

對于不可變對象(如 int, str, tuple 等),淺拷貝和深拷貝沒有區(qū)別,因?yàn)樗鼈儫o法被修改。但注意,如果元組中包含可變對象,深拷貝仍然會(huì)復(fù)制那些可變對象。

python
import copy

tup = (1, 2, [3, 4])
tup_copy = copy.copy(tup)
tup_deep = copy.deepcopy(tup)

print(tup_copy is tup) ? ? ? ?# True,元組本身不可變,copy 可能返回原對象
print(tup_deep is tup) ? ? ? ?# False,deepcopy 會(huì)遞歸復(fù)制內(nèi)部列表
print(tup_deep[2] is tup[2]) ?# False

六、淺拷貝與深拷貝的對比

特性淺拷貝  深拷貝    
復(fù)制層級(jí)只復(fù)制最外層對象遞歸復(fù)制所有層級(jí)
內(nèi)存占用小,共享內(nèi)部對象大,完全獨(dú)立  
速度
與原對象關(guān)系內(nèi)部可變對象會(huì)相互影響完全獨(dú)立,互不影響
適用場景簡單數(shù)據(jù)結(jié)構(gòu),無需完全隔離復(fù)雜嵌套結(jié)構(gòu),需要完全隔離

七、容易踩的坑

坑1:認(rèn)為 = 是拷貝

python
a = [1, 2, 3]
b = a
b.append(4)
print(a) ? # [1, 2, 3, 4] ? a 也被改了

很多人會(huì)以為 b = a 創(chuàng)建了一個(gè)副本,實(shí)際上只是多了一個(gè)引用。

坑2:混淆 copy() 與 deepcopy() 對嵌套結(jié)構(gòu)的影響

python
original = [[1, 2], [3, 4]]
shallow = original.copy()
shallow[0][0] = 99
print(original) ?# [[99, 2], [3, 4]] ?原數(shù)據(jù)被改了!

期望的是復(fù)制,卻因?yàn)闇\拷貝共享了內(nèi)部列表,導(dǎo)致原數(shù)據(jù)被意外修改。

坑3:深拷貝時(shí)遇到循環(huán)引用

python
import copy

a = []
b = [a]
a.append(b) ? # 形成循環(huán)引用

c = copy.deepcopy(a) ? # 默認(rèn)可以處理,不會(huì)無限遞歸
print(c) ?# [[[...]]]

deepcopy 內(nèi)部使用 memo 字典記錄已經(jīng)復(fù)制過的對象,可以安全處理循環(huán)引用。

坑4:認(rèn)為所有對象都能被深拷貝

有些對象(如文件對象、線程鎖、數(shù)據(jù)庫連接等)不能被復(fù)制,深拷貝會(huì)拋出異常。對于這類對象,通常需要自定義 __deepcopy__ 方法返回自身或合適的表示。

python
import copy

f = open('test.txt', 'w')
# copy.deepcopy(f) ? # TypeError: cannot pickle '_io.TextIOWrapper' object

八、實(shí)際應(yīng)用場景

場景1:防御性編程

當(dāng)需要將對象傳遞給不可信的函數(shù),且不希望函數(shù)修改原對象時(shí),可以用深拷貝。

python
def process(data):
? ? # 可能會(huì)修改 data,但不想影響外部
? ? data_local = copy.deepcopy(data)
? ? # ... 操作 data_local

場景2:緩存與狀態(tài)保存

在實(shí)現(xiàn)撤銷、重做功能時(shí),需要保存對象的歷史狀態(tài),深拷貝可以保證狀態(tài)獨(dú)立。

python
class Document:
? ? def __init__(self):
? ? ? ? self.content = []
? ? def save_state(self):
? ? ? ? return copy.deepcopy(self.content)
? ? def restore_state(self, state):
? ? ? ? self.content = state

場景3:多線程編程

多個(gè)線程需要獨(dú)立處理同一份數(shù)據(jù)副本時(shí),可以使用深拷貝避免競態(tài)條件。

場景4:配置管理

當(dāng)多個(gè)模塊需要基于同一份默認(rèn)配置生成自己的獨(dú)立配置時(shí),深拷貝可以防止互相干擾。

九、性能考量與最佳實(shí)踐

1. 避免不必要的深拷貝

深拷貝可能非常耗時(shí),尤其是對于大型對象。盡量只在必要時(shí)使用。

python
# 如果只需要復(fù)制一層,用淺拷貝
new_list = old_list[:]

# 如果內(nèi)部元素是不可變對象,淺拷貝就夠了
nums = [1, 2, 3]
new_nums = nums[:] ? # 安全,因?yàn)檎麛?shù)不可變

2. 自定義復(fù)制方法提高效率

對于自定義類,可以重寫 __copy__ 和 __deepcopy__ 來優(yōu)化復(fù)制行為,比如共享某些不必復(fù)制的部分。

3. 利用 copyreg 模塊注冊復(fù)制函數(shù)

對于無法直接復(fù)制的對象(如第三方庫中的類型),可以通過 copyreg 模塊注冊復(fù)制函數(shù)。

十、總結(jié)

1. 淺拷貝:創(chuàng)建新對象,但內(nèi)部元素是原對象的引用。適合簡單結(jié)構(gòu)或不需要完全隔離的場景。

2. 深拷貝:遞歸復(fù)制所有內(nèi)容,得到完全獨(dú)立的新對象。適合復(fù)雜嵌套結(jié)構(gòu)且需要完全隔離的場景。

3. 賦值(=)不是拷貝,只是引用綁定。

4. 對于不可變對象,淺拷貝與深拷貝差別不大,但若內(nèi)部包含可變對象,深拷貝仍然會(huì)復(fù)制。

5. 使用 copy 模塊時(shí)注意性能開銷,避免濫用深拷貝。

到此這篇關(guān)于Python深拷貝與淺拷貝實(shí)現(xiàn)及對比的文章就介紹到這了,更多相關(guān)Python深拷貝與淺拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解python opencv圖像混合算術(shù)運(yùn)算

    詳解python opencv圖像混合算術(shù)運(yùn)算

    這篇文章主要介紹了python opencv圖像混合算術(shù)運(yùn)算的相關(guān)知識(shí),本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 收集的幾個(gè)Python小技巧分享

    收集的幾個(gè)Python小技巧分享

    這篇文章主要介紹了收集的幾個(gè)Python小技巧分享,如獲得當(dāng)前機(jī)器的名字、獲取當(dāng)前工作路徑、獲取系統(tǒng)的臨時(shí)目錄等,需要的朋友可以參考下
    2014-11-11
  • Django實(shí)現(xiàn)drf搜索過濾和排序過濾

    Django實(shí)現(xiàn)drf搜索過濾和排序過濾

    當(dāng)我們需要對后臺(tái)的數(shù)據(jù)進(jìn)行過濾的時(shí)候,drf有兩種,搜索過濾和排序過濾。本文就詳細(xì)的介紹這兩種的實(shí)現(xiàn),感興趣的可以了解一下
    2021-06-06
  • 詳解用Python調(diào)用百度地圖正/逆地理編碼API

    詳解用Python調(diào)用百度地圖正/逆地理編碼API

    這篇文章主要介紹了詳解用Python調(diào)用百度地圖正/逆地理編碼API,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • python3發(fā)送request請求及查看返回結(jié)果實(shí)例

    python3發(fā)送request請求及查看返回結(jié)果實(shí)例

    這篇文章主要介紹了python3發(fā)送request請求及查看返回結(jié)果實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Python入門教程(三十四)Python的文件處理

    Python入門教程(三十四)Python的文件處理

    這篇文章主要介紹了Python入門教程(三十四)Python的文件處理,在Python中處理文件的主要是open()函數(shù),接下來我們就來一起看看open()函數(shù)的用法吧,需要的朋友可以參考下
    2023-05-05
  • Python中的Django框架基礎(chǔ)及安裝教程

    Python中的Django框架基礎(chǔ)及安裝教程

    本文介紹了Django框架的基本概念、安裝、項(xiàng)目創(chuàng)建和啟動(dòng)方法,以及路由配置、ORM思想和使用,Django是一個(gè)全??蚣?遵循MTV模式,提供自動(dòng)化工具和ORM,簡化了Web開發(fā)流程,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • python?import?logging問題

    python?import?logging問題

    這篇文章主要介紹了python?import?logging問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 利用python為PostgreSQL的表自動(dòng)添加分區(qū)

    利用python為PostgreSQL的表自動(dòng)添加分區(qū)

    這篇文章主要介紹了利用python為PostgreSQL的表自動(dòng)添加分區(qū),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Python全棧之for循環(huán)

    Python全棧之for循環(huán)

    這篇文章主要為大家介紹了Python for循環(huán),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11

最新評論

汤阴县| 汝南县| 静海县| 武清区| 色达县| 卢氏县| 嘉荫县| 南江县| 同德县| 仁怀市| 辉南县| 中江县| 荔波县| 阿瓦提县| 武夷山市| 枣阳市| 顺义区| 本溪市| 晋江市| 铜山县| 阿拉善左旗| 武汉市| 郎溪县| 黎川县| 永嘉县| 丽水市| 太原市| 清流县| 北京市| 论坛| 布尔津县| 吉木乃县| 图木舒克市| 灵寿县| 云龙县| 景东| 石家庄市| 古浪县| 广宁县| 莱州市| 浙江省|