1. 程式人生 > >Python中復制、深拷貝和淺拷貝的區別

Python中復制、深拷貝和淺拷貝的區別

ron 一份 謝謝 操作 完成 函數 技術 也會 python解釋器

深拷貝定義(deepcopy)

在Python中,由於一切皆對象,所以任何變量都可以被引用,也即可以被賦值給任何變量。但是在Python中,給變量賦值,是區分的,一般情況下,Python中的變量賦值都是淺拷貝,如果需要使用深拷貝,需要特別指定。

深拷貝是對原對象的“復制以及粘貼”,其實就是在內存中重新開辟了一個新的內存空間來存放這一份數據,兩個變量其實是兩個不一樣的變量,僅僅是數據值相同而已,對兩個變量的操作不會相互影響。

淺拷貝(copy)

在Python中進行數據的淺拷貝時,如果此時淺拷貝的數據是Python中的原子數據結構,比如str,int,float,tuple等不可變的原子數據結構,那麽在Python解釋器中,會給新賦值的變量開辟一個新的內存空間,且新的內存空間中存放的值和淺拷貝的數據值一致。

例如:

技術分享圖片

此時需要註意,Python中如果int數值小於一定的數的話,Python還是會引用同一個數據值,也就是a和b兩個變量的地址一樣。如:

技術分享圖片

且當改變a和b的數值時,地址也會發生改變,就相當於是a和b都是兩個指針,指向具體的存放數值的地址空間,如果修改完後a和b的數值一致,那麽a和b的地址也會一樣。如:

技術分享圖片

當對一些可變對象進行淺拷貝時,此時其實是對可變對象的二次引用,並沒有重新開辟新的內存空間。如:

技術分享圖片

從圖中可以看到,a和b都是對列表的引用,雖然a是先引用的該列表,但是他們在內存中的地址都是一樣的,也就是說他們其實是同一個列表的兩個不同的昵稱而已。

列表的兩種不同的賦值方式,“=”和切片操作,它們之間的區別如下:

“=”:該符號對於淺拷貝而言,其實就是將“=”兩邊的兩個不同的變量同時指向了同一個內存空間,且內存空間的值是相同的。當一個變量對內存空間中的數值進行了修改之後,在使用另一個變量去引用該內存空間中的變量時,數值也會改變,因為他們都指向同一個數據值。

切片操作:當時切片操作(a[start_index:end_index])對一個列表進行賦值給另外一個變量時,這時不再是兩個不同的變量同時指向一個內存地址空間中數據值,因為切片操作會返回一個新的列表,所以新的變量會接收一個新的列表,新的列表中的數據值就是切片之後的數據值,且在內存中的地址空間不一樣。如圖:

技術分享圖片

此時對c的任何操作與a(b)無關,因為a和b其實是同一個列表。

但是當列表中有可變數據結構時(list,dict等)就會出現不一樣的結果,因為在Python中,對於可變的數據類型,Python解釋器會給變量采用引用的方式對 可變的數據類型的數據 進行引用,為了節省內存空間。 如圖所示:

技術分享圖片

如果需要讓兩個變量能同時且獨立的操作該列表(列表中有可變的數據類型的數據),那麽就需要使用到深拷貝對數據進行直接到拷貝,而不是引用。此時需要使用到一個Python中的內書庫函數copy,copy庫中的deepcopy()方法可以對數據進行直接到拷貝(深拷貝),如圖所示:

技術分享圖片

從圖中可以看到,c是對a的深拷貝,b是對a的切片操作的淺拷貝,同時修改列表中的可變元素,可見c中的數據是存放在一個獨立的內存空間中的。

在Python對數據對象進行拷貝時,需要註意:

第一、非容器類型(比如數字、字符串和其它“原子”類型的對象,像代碼、類型和range對象等)沒有被拷貝一說,淺拷貝是用完全切片操作來完成。 第二、如果元組變量中只包含原子類型對象,對它的深拷貝將不會進行。 技術分享圖片 從圖中可以看到,tuple中都是“原子”類型的數據對象,此時對其進行深拷貝,但是查看內存中的地址,並沒有給b重新開辟一個新的內存空間,所以需要註意這一點。 技術分享圖片 但是如果tuple有可變的數據類型的對象時,深拷貝是起作用的。 ---------------------------------------------------------------------------------- 如果您覺得我的博客對您有一定的幫助,可以給我一點點的鼓勵,您的鼓勵是對我的最大的肯定,我會繼續努力。謝謝您。 支付寶: 微信支付: 技術分享圖片 技術分享圖片

Python中復制、深拷貝和淺拷貝的區別