Python列表的深復(fù)制和淺復(fù)制示例詳解
一、深復(fù)制與淺復(fù)制
列表是Python中自帶的一種數(shù)據(jù)結(jié)構(gòu),在使用列表時,拷貝操作不可避免,下面簡單討論一下列表的深復(fù)制(拷貝)與淺復(fù)制
首先看代碼:
l1 = [5, 4, 3, 2, 1] # 用兩種方法實現(xiàn)對列表l1的拷貝 l2 = l1 l3 = l1[:] print(l1) # [5, 4, 3, 2, 1] print(l2) # [5, 4, 3, 2, 1] print(l3) # [5, 4, 3, 2, 1] #修改l1 l1[0] = 9 print(l1) # [9, 4, 3, 2, 1] print(l2) # [9, 4, 3, 2, 1] print(l3) # [5, 4, 3, 2, 1]
我們發(fā)現(xiàn)修改l1的第一個元素后,l2的第一個元素跟著改變,而l3并沒有發(fā)生變化。Python內(nèi)置函數(shù)id()可以返回元素的地址,那么我們使用這個函數(shù)來看一下三個列表的地址:
print(id(l1)) # 2927957162504 print(id(l2)) # 2927957162504 print(id(l3)) # 2927923243528
從結(jié)果來看,l1和l2地址是一樣的,也就是說l1和l2指向的是同一塊內(nèi)存區(qū)域,顯然,通過 l2 = l1 操作,l1和l2都成了指向同一塊內(nèi)存地址的“指針”,也就是說這個操作是為l1取了一個別名,也可以說l2是l1的一個引用。用一張圖來解釋:
那么修改l1也就是在修改l2:
接下來看一下創(chuàng)建l3的過程,l3 = l1[:] ,這是將l1進(jìn)行切片,并將切片后的列表拷貝到l3所指向的內(nèi)存區(qū)域,同樣看圖:
也就是說l1和l3指向不同的內(nèi)存區(qū)域,那么修改l1并不會影響到l3:
通俗的來講,像l2這種,拷貝出來的對象和原對象的地址相同,為淺復(fù)制,像l3這種,分配新的內(nèi)存空間并拷貝原始內(nèi)容的,拷貝出來的對象和原對象的地址不同,為深復(fù)制。
二、復(fù)制列表內(nèi)元素的淺復(fù)制
在復(fù)制列表中的所有元素的時候,進(jìn)行淺復(fù)制
看一個比較有意思的東西,看代碼:
l1 = [1,2,3,[1,3]] l2 = l1[:] l1[3][1] = 9 print(l1) # [1, 2, 3, [1, 9]] print(l2) # [1, 2, 3, [1, 9]]
按照前面的理解,修改l1某個元素后,l2應(yīng)該不會發(fā)生改變,可結(jié)果卻與我們預(yù)想的結(jié)果大相徑庭,于是,我們不得不思考一下l2深復(fù)制到底復(fù)制了什么東西。實際上列表其實可以理解為一個“指針”,l1[3]是一個列表元素,l2[3]也是一個列表元素,執(zhí)行以下代碼:
print(id(l2[3])) # 2014816956232 print(id(l1[3])) # 2014816956232
我們發(fā)現(xiàn)l1[3]和l2[3]指向的地址是一樣的,也就是說在執(zhí)行 l2 = l1[:] 的時候,將一個地址拷貝了,所以修改l1[3]相當(dāng)于修改l2[3],所以才會出現(xiàn)上述結(jié)果,這更加說明了列表其實就是一個指向一片內(nèi)存區(qū)域的“指針”。那么我們是不是可以說列表l2深復(fù)制l1,但是對列表中每個元素進(jìn)行復(fù)制時進(jìn)行的是淺復(fù)制呢?答案顯而易見。
修改l1[3]中的元素:
三、copy()和deepcopy()
copy模塊可以幫助我們實現(xiàn)對象的復(fù)制操作
列舉一下其他的拷貝列表的方式:
l4 = l1 * 1 print(id(l4)) # 2927957916296 l5 = list(l1) print(id(l5)) # 2927957767816 import copy l6 = copy.copy(l1) print(id(l6)) # 2927956854024 l7 = copy.deepcopy(l1) print(id(l7)) # 2927958503368
我們可以看到,這幾種拷貝方式所得到的的新對象與原對象的地址都不相同了,并沒有按照字面意思(copy進(jìn)行淺復(fù)制,deepcopy進(jìn)行深復(fù)制),那么copy()和deepcopy()究竟有什么區(qū)別呢,繼續(xù)看代碼:
list1 = [1,2,3,[1,3]] list2 = list1[:] list3 = copy.copy(list1) list4 = copy.deepcopy(list1) list1[3][0] = 9 print(list1) # [1, 2, 3, [9, 3]] print(list2) # [1, 2, 3, [9, 3]] print(list3) # [1, 2, 3, [9, 3]] print(list4) # [1, 2, 3, [1, 3]] print(id(list1[3])) # 2927923172616 print(id(list2[3])) # 2927923172616 print(id(list3[3])) # 2927923172616 print(id(list4[3])) # 2927967190728
可以發(fā)現(xiàn)copy()和前面提到的用 [:] 進(jìn)行拷貝沒有本質(zhì)上的區(qū)別,對列表中的每個元素進(jìn)行復(fù)制時進(jìn)行的是淺拷貝,而deepcopy()在復(fù)制列表中的每個元素的時候,進(jìn)行的是深拷貝。
總結(jié)
到此這篇關(guān)于Python列表的深復(fù)制和淺復(fù)制的文章就介紹到這了,更多相關(guān)Python列表深復(fù)制和淺復(fù)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中常見進(jìn)制之間的轉(zhuǎn)換方式
這篇文章主要介紹了python中常見進(jìn)制之間的轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05Python Threading 線程/互斥鎖/死鎖/GIL鎖
這篇文章主要介紹了Python Threading 線程/互斥鎖/死鎖/GIL鎖的相關(guān)知識,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07Python實現(xiàn)繪制M2貨幣供應(yīng)率曲線
這篇文章主要為大家詳細(xì)介紹了如何利用Python語言實現(xiàn)繪制M2貨幣供應(yīng)率曲線,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-06-06python登錄WeChat 實現(xiàn)自動回復(fù)實例詳解
在本篇內(nèi)容里小編給大家整理的是關(guān)于python登錄WeChat 實現(xiàn)自動回復(fù)的相關(guān)實例內(nèi)容以及知識點總結(jié),有興趣的朋友們參考下。2019-05-05