亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python中深淺拷貝的區(qū)別詳細分析

 更新時間:2023年06月13日 15:30:22   作者:某學酥?Kevin  
深拷貝和淺拷貝都是對原對象的拷貝,都會生成一個看起來相同的對象,下面這篇文章主要給大家介紹了關于Python中深淺拷貝的區(qū)別的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

簡而言之:

深淺拷貝的區(qū)別關鍵在于拷貝的對象類型是否可變。

我們可以總結出以下三條規(guī)則:

  • 對于可變對象來說,深拷貝和淺拷貝都會開辟新地址,完成對象的拷貝
  • 而對于不可變對象來說,深淺拷貝都不會開辟新地址,只是建立引用關聯
    ,等價于賦值
  • 對于復合對象來說,淺拷貝只考慮最外層的類型,復合類型數據中的元
    素仍為引用關系;而深拷貝對復合對象遞歸應用前兩條規(guī)則

背后的邏輯也很容易理解,我們可以在 Python 的官方文檔里找到如下解釋:

Python 的賦值語句不復制對象,而是創(chuàng)建目標和對象的綁定關系。對于自身可變,或包含可變項的集合,有時要生成副本用于改變操作,而不必改變原始對象。

  • 不可變數據(3 個):Number(數字)、String(字符串)、Tuple(元組);
  • 可變數據(3 個):List(列表)、Dictionary(字典)、Set(集合)。

下面我們通過對不同類型的對象進行深淺拷貝來逐條說明上述規(guī)則:

不可變對象

以元組(tuple)為例:

import copy
 
tup1 = (991, "abc")
tup2 = copy.copy(tup1) # 淺拷貝
# tup2 = tup1 # 在這個例子里淺拷貝等價于賦值
 
print(id(tup1))
print(id(tup2))
 
print(tup1 == tup2)
print(tup1 is tup2)
 
# 2457279675264
# 2457279675264
# True
# True
 
tup2 = copy.deepcopy(tup1) # 深拷貝
 
print(id(tup1))
print(id(tup2))
 
print(tup1 == tup2)
print(tup1 is tup2)
 
# 1291830377344
# 1291830377344
# True
# True

我們可以看到,對于不可變對象,深拷貝還是淺拷貝都不會為我們對象建立真正的副本,tup2 和 tup1的地址完全相同,實際上引用的是同一個對象。

可變對象

以列表(list)為例: 

import copy
 
lis1 = [991, "abc", (9, 993), [994, 995], [888,887], {"name": "Tom"}, (996, [997, 998]), (888,(886, 886))]
lis2 = copy.copy(lis1) # 淺拷貝
 
print(id(lis1))
print(id(lis2))
 
print(lis1 == lis2)
print(lis1 is lis2)
 
# 2491304912896
# 2491304912960
# True
# False
 
lis2 = copy.deepcopy(lis1) # 深拷貝
print(id(lis1))
print(id(lis2))
 
print(lis1 == lis2)
print(lis1 is lis2)
 
# 2841088174144
# 2841088174208
# True
# False

可以看到,對于可變對象來說,深拷貝和淺拷貝都會開辟新地址,完成對象的拷貝。

復合對象

其實上面例子中的列表同時還是一個復合對象(即包含其他對象的對象)。

對于復合對象來說,淺拷貝只考慮最外層的類型,復合類型數據中的元素仍為引用關系。深拷貝對復合對象遞歸應用前兩條規(guī)則。

import copy
tup3 = (991, "abc", [])
tup4 = copy.copy(tup3) # 淺拷貝
print(tup3 is tup4) # True
print(tup3[-1] is tup4[-1]) # True
lis1 = [991, "abc", (9, 993), [994, 995], [888,887], {"name": "Tom"}, (996, [997, 998]), (888,(886, 886))]
lis2 = copy.copy(lis1) # 淺拷貝
print(lis1 is lis2) # False
# 雖然 lis1 和 lis2 的地址不同,但其中的每個元素都各自指向同一個對象
print(lis1[0] is lis2[0]) # True
print(lis1[1] is lis2[1]) # True
print(lis1[2] is lis2[2]) # True
print(lis1[3] is lis2[3]) # True
print(lis1[4] is lis2[4]) # True
print(lis1[5] is lis2[5]) # True
print(lis1[6] is lis2[6]) # True
print(lis1[7] is lis2[7]) # True

可以看到對于復合對象,其最外層的邏輯和前文提到的相同,即可變對象開辟新地址,不可變對象不開辟新地址。但復合對象內的元素全部只是建立引用關聯,地址相同。

而深拷貝還需確認復合對象中的所有元素是否都不可變然后在對元素遞歸應用前兩條規(guī)則。只要復合對象本身是可變的或者其中存在可變對象,則都會完成拷貝。

import copy
lis1 = [991, "abc", (9, 993), [994, 995], [888,887], {"name": "Tom"}, (996, [997, 998]), (888,(886, 886))]
lis2 = copy.deepcopy(lis1) # 深拷貝
print(lis1 is lis2) # False,列表是可變對象,深復制后地址改變
print(lis1[0] is lis2[0]) # True,索引0是整數,不可變,地址不變
print(lis1[3] is lis2[3]) # False, 索引3是列表,可變,地址改變
tup3 = (991, "abc", [])
tup4 = copy.deepcopy(tup3) # 深拷貝
print(tup3 is tup4) # False,雖然 tup3 是不可變對象,但其內部存在可變對象,所以深復制后地址仍然改變
print(tup3[0] is tup4[0]) # True,索引 0 是整數,不可變,地址不變
print(tup3[1] is tup4[1]) # True,索引 3 是字符串,不可變,地址不變
print(tup3[2] is tup4[2]) # False,索引 3 是列表,可變,地址改變

參考:

copy — Shallow and deep copy operations — Python 3.10.7 documentation(Python3 文檔)

補充:下面解釋可變類型和不可變類型的嵌套使用

(1)可變類型:

淺拷貝和深拷貝只要最外層是可變類型都會生成新的對象

  • [] 或者{}, 淺拷貝和深拷貝都會生成新的對象
  • [[],[]]列表的嵌套,可變類型嵌套了可變類型,淺拷貝:只拷貝最外層,會生成新的對象,內層是引用。深拷貝:外層和內層都會進行拷貝,都是全新的對象,都有獨立的存儲空間
  • [(),()] 外層可變,內層不可變,淺拷貝:只拷貝最外層,會生成新的對象,內層是引用。深拷貝:外層和內層都會進行拷貝,外層會生成新對象,但是由于內層是不可變類型,所以內層依然是引用
  • [(),[]] 外層可變,內層有一個是可變,淺拷貝:只拷貝最外層,會生成新的對象,內層是引用。深拷貝:外層和內層都會進行拷貝,外層會生成新對象,內層可變對象會生成新對象,內層不可變對象是引用

(2)不可變類型:

最外層是不可變類型,淺拷貝就一定是引用

  • Number、字符串或者(), 淺拷貝和深拷貝都是引用
  • ([],[]), copy淺拷貝:只會拷貝最外層,內層只是引用,但是最外層是不可變,拷貝之后毫無意義,僅僅是引用關系。deepcopy:從外層到內層都會拷貝,內層是可變,為了達到和原來的數據完全隔離,會生成全新的對象
  • ((),()) 完全不可變,拷貝了之后如果生成新的數據也無法修改,所以不管深拷貝還是淺拷貝都是引用
  • ((),[]) 外層不可變,但是內層有一個是可變,copy依然是引用,deepcopy,會生成新的對象,內層的不可變類型是引用,可變類型會生成新的對象。

總結

到此這篇關于Python中深淺拷貝的區(qū)別的文章就介紹到這了,更多相關Python深淺拷貝的區(qū)別內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python使用pickle進行序列化和反序列化的示例代碼

    Python使用pickle進行序列化和反序列化的示例代碼

    這篇文章主要介紹了Python使用pickle進行序列化和反序列化,幫助大家更好的理解和使用python的pickle庫,感興趣的朋友可以了解下
    2020-09-09
  • python3操作redis實現List列表實例

    python3操作redis實現List列表實例

    本文主要介紹了python3操作redis實現List列表實例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 利用jupyter網頁版本進行python函數查詢方式

    利用jupyter網頁版本進行python函數查詢方式

    這篇文章主要介紹了利用jupyter網頁版本進行python函數查詢方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Cython處理C字符串的示例詳解

    Cython處理C字符串的示例詳解

    如果你在使用 Cython 加速 Python 時遇到了瓶頸,但還希望更進一步,那么可以考慮將數據的類型替換成 C 的類型,所以本文為大家介紹了Cython處理C字符串的方法,希望對大家有所幫助
    2023-01-01
  • 舉例講解Linux系統(tǒng)下Python調用系統(tǒng)Shell的方法

    舉例講解Linux系統(tǒng)下Python調用系統(tǒng)Shell的方法

    這篇文章主要介紹了舉例講解Linux系統(tǒng)下Python調用系統(tǒng)Shell的方法,包括用Python和shell讀取文件某一行的實例,需要的朋友可以參考下
    2015-11-11
  • Pytest如何使用mark的方法

    Pytest如何使用mark的方法

    本文主要介紹了Pytest如何使用mark的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • macbook如何徹底刪除python的實現方法

    macbook如何徹底刪除python的實現方法

    本文主要介紹了macbook如何徹底刪除python的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • Python bytes string相互轉換過程解析

    Python bytes string相互轉換過程解析

    這篇文章主要介紹了Python bytes string相互轉換過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Python中isinstance和hasattr的實現示例

    Python中isinstance和hasattr的實現示例

    本文詳細介紹了Python中的兩個內置函數isinstance和hasattr,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-12-12
  • 入門tensorflow教程之TensorBoard可視化模型訓練

    入門tensorflow教程之TensorBoard可視化模型訓練

    在本篇文章中,主要介紹 了TensorBoard 的基礎知識,并了解如何可視化訓練模型中的一些基本信息,希望對大家的TensorBoard可視化模型訓練有所幫助
    2021-08-08

最新評論