首頁 後端開發 Python教學 詳解Python淺拷貝、深拷貝及引用機制

詳解Python淺拷貝、深拷貝及引用機制

Mar 23, 2017 pm 05:43 PM
python

這禮拜碰到一些問題,然後意識到基礎知識一段時間沒鞏固的話,還是有遺忘的部分,還是需要溫習,這裡做份筆記,記錄一下

##前續
先簡單描述下碰到的題目,要求是寫出2個print的結果


详解Python浅拷贝、深拷贝及引用机制
#可以看到,a指向了一個列表list對象,在Python中,這樣的賦值語句,其實內部意義是指a指向這個list所在記憶體位址,可以看作類似指標的概念。

而b,注意,他是把a對象包進一個list,並且乘以5,所以b的樣子應該是一個大list,裡面元素都是a

而當a對象進行了append操作後,其實,隱含的意思是,內存中的這個list進行了修改,所有對此對象進行引用的對象,都會發生改變

我將a的id打印出來,並且,同時印出b這個物件中所包含的元素a的id,這樣可以看到,在b這個list中,每個元素的id,和a是一樣的


详解Python浅拷贝、深拷贝及引用机制
#我們可以看到,a對象的id(記憶體位址)為10892296,雖然b把a包進了新的list,但是,這個元素引用的,還是相同位址的對象,可以用下圖來解釋##在


详解Python浅拷贝、深拷贝及引用机制 #之後,我們對a進行了append操作,由於list是可變對象,所以,他的記憶體位址並沒有改變,但是,對於記憶體中這個位址的引用的所有對象,都會被一同改變可以從上面測試圖分割線下半部分看出來.

由此,引出了對Python引用機制和淺複製及深複製的複習


Python的引用機制



引用機制案例1
由上面的例子,我們可以看到,python的引用傳遞,最終結果是讓2個物件都引用記憶體中同一塊區域的內容

所以我們來看一下下面的範例

B透過A,同樣引用了id為17446024的地址的內容,2者的id(記憶體位址)都是一毛一樣的

所以,透過A的操作 A[0]=3  或是  A[3].append(6)  ,都會對這塊記憶體中的內容進行修改(因為list是可變對象,所以記憶體位址並不會改變,這個後面再講)

這個是最基本的引用案例(另外說句,由於A和B都指向了同一塊記憶體位址,所以經由B修改的內容,也能反映到A上面去)



详解Python浅拷贝、深拷贝及引用机制
#引用機制案例2
我們再來看一個案例

看題目貌似是會把元素2替換成本身這個列表,結果也許應該是A=[1,[1,2,3],3]

但其實不是! !你可以看到,紅框中部分,中間有無限多個嵌套

為什麼會這樣呢?

其實是因為,A指向的是[1,2,3]這個列表,在這個例子中,只是把A的第2個元素,指向了A對象本身,所以說,只是A的結構發生了變化!但是,A還是指向那個物件

我們可以透過印A的id來看,他的指向是沒有改變的! !



详解Python浅拷贝、深拷贝及引用机制 來看一下,A的指向並沒有改變



详解Python浅拷贝、深拷贝及引用机制 那如果我們要達到最後輸出效果是[ 1,[1,2,3],3]的效果,該如何來操作?

這裡,我們就要用到淺複製了,用法可以如下




详解Python浅拷贝、深拷贝及引用机制
#淺複製和深複製

#淺複製
#
現在,就來說說淺複製和深複製,上面的方法實際上只是進行了淺複製,shallow copy,含義是他是對原來引用的對象進行了複製,但是不再引用同一對像地址

看下面的例子,B透過B = A[:] 操作,來進行了淺複製,你可以看到,淺複製之後,A和B引用的記憶體位址已經是不同的了

但是,A和B內部的元素的引用位址,還是相同的,這點要非常注意!是有差別的! ! !

A和B的引用記憶體位址的不同,帶來的效果是,你在B上面進行的操作,並不會影響到A。

详解Python浅拷贝、深拷贝及引用机制

淺拷貝歸納:

#所以淺拷貝,可以歸納為,複製一份引用,新的物件和原來的物件的參考被區分開,但是內部元素的位址引用還是相同的

但是淺複製也會有問題,問題在哪裡呢?就是碰到有巢狀的情況,例如下面的情況可以看到,我給B賦值了一份A的淺複製,這樣A和B的id(記憶體位址)就不一樣了。

所以,當我修改A[0]=8的時候,B不會被影響到,因為他們A和B兩者是獨立的引用,但是這裡中間有一個嵌套的列表[4 ,5,6]

這個[4,5,6]我們可以理解為:A和B也共同引用著,也就是對於A和B的第二個元素來說,他們還是指向同一塊記憶體位址的。

另外要說一句,由於int是不可變型,所以,把A[0]修改成8之後,他的引用位址就變了!就和B[0]這個元素的引用區分開了。

详解Python浅拷贝、深拷贝及引用机制

深複製

那要如何面對這樣的情況呢?就要用到python模組裡面的copy模組了

copy模組有2個功能

1: copy.copy(你要複製的物件) : 這個是淺拷貝,和前面對list進行的[:] 操作性質是一樣的

2: copy.deepcopy(你要複製的物件) : 這個是深拷貝,他除了和淺拷貝一樣,會新產生一份物件的引用,另外對於內部的元素,都會新生成引用,以獨立分開.

看下面的例子,當你給B賦值一份A的深複製之後,他倆可以說是完全獨立開了,無論你修改的是A裡面的不可變元素,還是修改A裡面嵌套的可變元素,結果都不會影響到B

我的理解是:深複製可以稱之為遞歸拷貝,他會把所有嵌套的可變元素都拷貝一下,然後獨立引用出來.

详解Python浅拷贝、深拷贝及引用机制

#深複製歸納:

深複製的效果,除了和淺複製一樣,將物件的引用新生成一份引用之外,內部所有嵌套的元素,他都會幫你一一獨立開.

自己畫了2張圖,以表示淺複製和深複製的效果區別

需要說明的是,雖然淺複製之後,列表內不可變元素的引用地址還是相同的,但是,正因為他們是不可變元素,所以,在其中任意不可變元素被改變之後,引用位址都會是新的,而不會影響原來的引用位址。



详解Python浅拷贝、深拷贝及引用机制

详解Python浅拷贝、深拷贝及引用机制

#總結

所以,到這裡,淺複製和深複製的機制,基本上理解了。

另外還有特殊情況需要說明

對於不可變類型:int, str, tuple, float 這樣的元素來說,沒有拷貝這個說法,他們被修改之後,引用地址就是直接改變了,如下面

详解Python浅拷贝、深拷贝及引用机制

但是,如果不可變類型內部有嵌套的可變類型的時候,還是可以使用深複製的

#详解Python浅拷贝、深拷贝及引用机制

另外要提醒一句,平常我們用的最多的直接賦值(或可以說是直接傳遞引用)的方法,例如下面的例子

他是將a和b兩個可變元素同時指向一個記憶體位址,所以,任何改變都是波及到a和b的

详解Python浅拷贝、深拷贝及引用机制

#最後

可變類型:list , set , dict

不可變類型:int, str , float , tuple

淺複製方法:[:] , copy.copy() ,  使用工廠函數(list/dir/set )

深複製方法:copy.deepcopy()


以上是詳解Python淺拷貝、深拷貝及引用機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1327
25
PHP教程
1273
29
C# 教程
1252
24
PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

See all articles