簡單理解Python中的深拷貝與淺拷貝

I. 簡介

深拷貝會遞歸的創建一個完全獨立的對象副本,包括所有嵌套的對象,而淺拷貝只復制嵌套對象的引用,不復制嵌套對象本身。

簡單來說就是兩者都對原對象進行了復制,因此使用is運算符來比較新舊對象時,返回的都是False(都開辟了新的內存);兩者區別在于對嵌套對象有沒有進行遞歸的復制。淺拷貝沒有給嵌套對象復制并分配新內存,用is來比較嵌套對象時返回的是True;而深拷貝對嵌套對象開辟了進行了復制并分配新內存,用is來比較嵌套對象時返回的是False。

一個例子如下,我們分別對鏈表的頭結點執行深拷貝與淺拷貝:

# 原鏈表 ↓
a1 -> b1 -> c1 -> d1 -> e1
# 淺拷貝 ↓ 對于嵌套對象b1, c1, ..., 直接采用了原有引用
a2 -> b1 -> c1 -> d1 -> e1
# 深拷貝 ↓ 對于嵌套對象,同樣開辟了內存空間將其復制
a2 -> b2 -> c2 -> d2 -> e2

從代碼實現來講,深拷貝可以用copy庫的deepcopy方法實現;淺拷貝除了用copy庫的copy方法,還有許多其他的實現途徑,接下來我們將進行介紹。


II. 列表

A. 首先要注意一點,對于常用的等號賦值操作,這一操作并沒有進行任何拷貝,只是創建了對現有對象的一個新引用:

arr1 = [1, 2, 3, 4]
arr2 = arr1
print(arr2 is arr1)  # True
arr2[0] = 0
print(arr1)  # [0, 2, 3, 4]

B. 對列表進行切片屬于淺拷貝操作:

arr1 = [1, 2, 3, 4]
arr2 = arr1[:]
print(arr2 is arr1)  # False
arr2[0] = 0
print(arr1)  # [1, 2, 3, 4]

C. 淺拷貝并不會復制嵌套對象:

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1[:]
print(arr2 is arr1)  # False(最外層被復制)
print(arr2[-1] is arr1[-1])  # True(嵌套對象沒有被復制)
arr2[-1][0] = 0 
print(arr1)  # [1, 2, 3, [0, 5, 6]](被修改)

D. 深拷貝才會復制嵌套對象:

import copy
arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = copy.deepcopy(arr1)
print(arr2 is arr1)   # False
print(arr2[-1] is arr1[-1])   # False(嵌套對象也被復制)
arr2[-1][0] = 0 
print(arr1)   # [1, 2, 3, [4, 5, 6]](未修改)

E. 使用數據類型本身的構造器仍屬于淺拷貝:

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = list(arr1)  # 使用構造器創建新對象, 屬于淺拷貝
print(arr2 is arr1)   # False
print(arr2[-1] is arr1[-1])  # True
arr2[-1][0] = 0 
print(arr1)   # [1, 2, 3, [0, 5, 6]]

F. 對列表進行修改所返回的新列表也屬于淺拷貝(先淺拷貝再修改):

arr1 = [1, 2, 3, [4, 5, 6]]
arr2 = arr1 + []  # 先淺拷貝再修改
print(arr2 is arr1)  # False
print(arr2[-1] is arr1[-1])  # True
arr2[-1][0] = 0 
print(arr1)  # [1, 2, 3, [0, 5, 6]]

III. 字符串

A. Python中的字符串是不可變對象。因此,如果對其進行完整切片[:],可以發現這一過程并沒有對字符串本身進行修改。那么Python此時只會直接記錄原字符串對象的引用,不進行任何拷貝。從設計動機的角度理解,既然本身不可修改,并且進行的切片操作也沒有進行修改,那么復制的意義不大,所以干脆不進行復制:

s1 = "1234"
s2 = s1[:]
print(s2 is s1)  # True(引用的內容相同)

B. 以上結論同樣適用于對字符串進行"假修改",此時也不會進行任何拷貝:

s1 = "1234"
s2 = s1 + ""
print(s2 is s1)  # True(沒有進行實質修改)

C. 想要進行拷貝,那就得對字符串進行實質修改。如果切片運算改變了原字符串的內容,由于字符串是不可變的,因此只能開辟一個新的內存,來存儲修改后的字符串。此時進行了拷貝過程。注意,由于字符串本身沒法嵌套對象,因此這里不區分深拷貝與淺拷貝:

s1 = "1234"
s2 = s1[::-1][::-1] # 進行兩次修改,翻轉兩次
print(s2 is s1) # False
print(s2) # 1234
s3 = s1 + "5" 
print(s3 is s1) # False

D. 使用構造方法str,也不會進行任何拷貝,只是創建了另一個指向原字符串對象的引用:

s1 = "1234"
s2 = str(s1)
print(s2 is s1)  # True

E. 使用copy或deepcopy都不能對字符串內容進行拷貝,只會新增一個引用:

import copy
s1 = "1234"
s2 = copy.copy(s1)
s3 = copy.deepcopy(s1)
print(s2 is s1)  # True
print(s3 is s1)  # True

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/43129.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/43129.shtml
英文地址,請注明出處:http://en.pswp.cn/news/43129.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java把數字轉換成漢字 java 數字轉漢字

使用java將數字轉化為中文漢字_java數字轉中文_javaerly的博客-CSDN博客 package com.unicom.apartment.utils;public class NumUtil {public static String convert(int number) {if(number < 0){return "";}if(number 1){return "當天";}//數字對應的…

C#實現普通的語音播報

Windows有文字轉語音功能&#xff0c;C#提供了調用的類庫Interop.SpeechLib.dll 使用方法很簡單&#xff0c;在你的項目中添加Interop.SpeechLib.dll引用&#xff0c;在類中引用&#xff1a; using SpeechLib;這里提供一個CVoice類 幫助實現語音播報 public class CVoice{pri…

【5G 核心網】5G 多PDU會話錨點技術介紹

博主未授權任何人或組織機構轉載博主任何原創文章&#xff0c;感謝各位對原創的支持&#xff01; 博主鏈接 本人就職于國際知名終端廠商&#xff0c;負責modem芯片研發。 在5G早期負責終端數據業務層、核心網相關的開發工作&#xff0c;目前牽頭6G算力網絡技術標準研究。 博客…

Spring Boot(六十四):SpringBoot集成Gzip壓縮數據

1 實現思路 2 實現 2.1 創建springboot項目 2.2 編寫一個接口,功能很簡單就是傳入一個Json對象并返回 package com.example.demo.controller;import com.example.demo.entity.Advertising; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframewo…

LeetCode150道面試經典題-- 加一(簡單)

1.題目 給定一個由 整數 組成的 非空 數組所表示的非負整數&#xff0c;在該數的基礎上加一。 最高位數字存放在數組的首位&#xff0c; 數組中每個元素只存儲單個數字。 你可以假設除了整數 0 之外&#xff0c;這個整數不會以零開頭。 2.示例 示例 1&#xff1a; 輸入&am…

excel提示更新外部引用文件 這個提示能手動禁用

是的&#xff0c;你可以手動禁用 Excel 中的更新外部引用文件的提示。這些步驟可能因 Excel 版本而有所不同&#xff0c;以下是一般的步驟&#xff1a; 1. **打開 Excel**&#xff1a; 2. **進入“選項”**&#xff1a; - 在 Excel 中&#xff0c;點擊頂部菜單中的“文件”…

網絡通信原理傳輸層TCP三次建立連接(第四十八課)

ACK :確認號 。 是期望收到對方的下一個報文段的數據的第1個字節的序號,即上次已成功接收到的數據字節序號加1。只有ACK標識為1,此字段有效。確認號X+1SEQ:序號字段。 TCP鏈接中傳輸的數據流中每個字節都編上一個序號。序號字段的值指的是本報文段所發送的數據的第一個字節的…

「UG/NX」Block UI 面收集器FaceCollector

?博客主頁何曾參靜謐的博客??文章專欄「UG/NX」BlockUI集合??全部專欄「UG/NX」NX二次開發「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序設計「C/C+&#

LangChain手記 Question Answer 問答系統

整理并翻譯自DeepLearning.AILangChain的官方課程&#xff1a;Question Answer&#xff08;源代碼可見&#xff09; 本節介紹使用LangChian構建文檔上的問答系統&#xff0c;可以實現給定一個PDF文檔&#xff0c;詢問關于文檔上出現過的某個信息點&#xff0c;LLM可以給出關于該…

【vue】項目基礎環境搭建、css樣式重置與公用

nodejs環境 nodejs是當下前端工程化開發必不可少的環境, 使用 nodejs的 npm功能來管理依賴包 查看node 和 npm的版本 node -v #查看node版本npm -v #查看npm版本 git版本控制 git版本控制工具是目前最為流行的分布式版本管理工具,代碼的**提交, 檢出, 日志**, 都需要通過git完…

Matplotlib數據可視化(二)

目錄 1.rc參數設置 1.1 lines.linestype取值 1.2 lines.marker參數的取值 1.3 繪圖中文預設 1.4 示例 1.4.1 示例1 1.4.2 示例2 1.rc參數設置 利用matplotlib繪圖時為了讓繪制出的圖形更加好看&#xff0c;需要對參數進行設置rc參數設置。可以通過以下代碼查看matplotli…

C++11并發與多線程筆記(8) condition_variable、wait、notify_one、notify_all

C11并發與多線程筆記&#xff08;8&#xff09; condition_variable、wait、notify_one、notify_all 1、條件變量condition_variable、wait、notify_one、notify_all1.1 std::condition_variable1.2 wait()1.3 notify_one()1.4 notify_all() 2、深入思考 1、條件變量condition_…

JS內存泄漏

JS內存泄漏 1.意外的全局變量 全局變量的生命周期很長&#xff0c;直到頁面關閉&#xff0c;它都存活&#xff0c;所以全局變量上的內存一直都不會被回收 當全局變量使用不當&#xff0c;沒有及時回收&#xff08;手動賦值null&#xff09;&#xff0c;或者拼寫錯誤等將某個變…

[Machine Learning] decision tree 決策樹

&#xff08;為了節約時間&#xff0c;后面關于機器學習和有關內容哦就是用中文進行書寫了&#xff0c;如果有需要的話&#xff0c;我在目前手頭項目交工以后&#xff0c;用英文重寫一遍&#xff09; &#xff08;祝&#xff0c;本文同時用于比賽學習筆記和機器學習基礎課程&a…

【算法學習】兩數之和II - 輸入有序數組

題目描述 原題鏈接 給你一個下標從 1 開始的整數數組 numbers &#xff0c;該數組已按 非遞減順序排列 &#xff0c;請你從數組中找出滿足相加之和等于目標數 target 的兩個數。如果設這兩個數分別是 numbers[index1] 和 numbers[index2] &#xff0c;則 1 < index1 < …

Springboot MultipartFile文件上傳與下載

yml文件配置是否可以上傳及上傳附件大小 servlet:multipart:# 允許文件上傳enabled: true# 單個文件大小max-file-size: 20MB# 設置總上傳的文件大小max-request-size: 50MB /*** param files* param request* Description 上傳文件* Throws* Return java.util.List* Date 202…

南大通用數據庫(Gbase 8s) 創建UDR外部函數

一、在使用 date_format、from_unixtime、to_days、yearweek 函數時&#xff0c;Gbase 8s 數據庫不支持&#xff0c;可以使用創建 UDR 外部函數來實現 二、登錄命令控制臺或者使用 navicat 連接 Gbase 數據庫 這里使用 navicat &#xff0c;點擊新增連接選擇 PostGreSql 驅動…

動手學深度學習—卷積神經網絡LeNet(代碼詳解)

1. LeNet LeNet由兩個部分組成&#xff1a; 卷積編碼器&#xff1a;由兩個卷積層組成&#xff1b;全連接層密集塊&#xff1a;由三個全連接層組成。 每個卷積塊中的基本單元是一個卷積層、一個sigmoid激活函數和平均匯聚層&#xff1b;每個卷積層使用55卷積核和一個sigmoid激…

LeetCode--HOT100題(35)

目錄 題目描述&#xff1a;23. 合并 K 個升序鏈表&#xff08;困難&#xff09;題目接口解題思路1代碼解題思路2代碼 PS: 題目描述&#xff1a;23. 合并 K 個升序鏈表&#xff08;困難&#xff09; 給你一個鏈表數組&#xff0c;每個鏈表都已經按升序排列。 請你將所有鏈表合…

UDP 的報文結構以及注意事項

UDP協議 1.UDP協議端格式 1.圖中的16位UDP長度,表示整個數據報(UDP首部UDP數據)的最大長度 2.若校驗和出錯,會直接丟棄 2.UDP的報文結構 UDP報文主體分為兩個部分:UDP報頭(占8個字節)UDP載荷/UDP數據 1.源端口號 16位,2個字節 2.目的端口號 16位,2個字節 3.包長度 指示了…