1. 程式人生 > >python 淺拷貝與深拷貝

python 淺拷貝與深拷貝

python 變量 淺拷貝 深拷貝

python變量在內存中是這樣存儲的:

技術分享圖片

在python中,一切都是對象,對象的存儲是引用存儲,存儲的只是變量的值所在的內存地址,而不是這個變量的值本身。


技術分享圖片


如果對值進行修改,其實是在內存中新創建一個值,把變量指向這個值的地址


技術分享圖片


可以看出地址發生了改變

如果是兩個值相等,那麽改變其中一個不會影響另一個

技術分享圖片


a=b時a,b指向同一個地址

改變a的值後b不會改變

技術分享圖片


說明是在內存中新創建了一個值,a指向了這個值的地址

技術分享圖片



這是基本類型的存儲

python中可以分兩大類數據類型,一種是基礎數據類型,如 int str float,long ,bool等基礎類型,另一種是list,tulpe,dict,set等復雜類型,list,tulpe,dict,set中包含基礎類型

由於python中的變量都是采用的引用存儲,而list,tuple,dict這種數據結構可以包含基礎數據類型,這就導致了每個變量中都存儲了這個變量的地址,而不是值本身;對於復雜的數據結構來說,裏面的存儲的也只是每個元素的地址而已。

如果是list列表的存儲形式:

L = [1,2,3,'a','b','c']

print(id(L))

變量L的地址為



技術分享圖片

技術分享圖片

每個元素的地址為

L = [1,2,3,'a','b','c']

#print(id(L))

print(id(L[0]))

print(id(L[1]))

print(id

(L[2]))

print(id(L[3]))

print(id(L[4]))

技術分享圖片

技術分享圖片


技術分享圖片

技術分享圖片


L所存的就是這些元素的地址

在內存表現形式為:

技術分享圖片

將列表L的內容賦值給另一個變量和字符的操作一樣

L = [1,2,3,'a','b','c']

Y = L

print(L)

print(Y)

print(id(L))

print(id(Y))


技術分享圖片


技術分享圖片


對L追加元素:

L = [1,2,3,'a','b','c']

Y = L

print(L)

print(Y)

print(id(L))

print(id(Y))

L.append("f")

print

(L)

print(Y)

print(id(L))

print(id(Y))


技術分享圖片


技術分享圖片

如果重新賦值或者說重新初始化,那麽會重新分配新的內存空間

L = [1,2,3,'a','b','c']

Y = L

print(L)

print(Y)

print(id(L))

print(id(Y))

L.append("f")

print(L)

print(Y)

print(id(L))

print(id(Y))

L = ['a','b','c']

print(L)

print(Y)

print(id(L))

print(id(Y))


技術分享圖片

技術分享圖片


也就是說如果在地址上操作那麽指向這兩個地址的變量的內容都會改變但是地址指向不變

如果重新賦值,那麽重新賦值的那個變量地址就會指向新的內存地址

這就是變量賦值的過程

淺拷貝

淺拷貝:不管多麽復雜的數據結構,淺拷貝都只會copy一層。

基礎數據的拷貝,不管淺拷貝還是深拷貝都一樣都會重新分配內存地址

#基礎數據拷貝

import copy

L = [1,2,3,'a','b']

M = copy.copy(L)

print(L)

print(M)

print(id(L))

print(id(M))


技術分享圖片


技術分享圖片


import copy

L = [1,2,3,'a','b']

M = copy.copy(L)

print(L)

print(M)

print(id(L))

print(id(M))

#給L追加一個元素M不會變

L.append("c")

print(L)

print(M)

print(id(L))

print(id(M))


技術分享圖片


技術分享圖片


深拷貝基礎數據:

import copy

L = [1,2,3,'a','b']

M = copy.deepcopy(L)

print(L)

print(M)

print(id(L))

print(id(M))

#給L追加一個元素M不會變

L.append("c")

print(L)

print(M)

print(id(L))

print(id(M))


技術分享圖片


技術分享圖片

結果和淺拷貝一樣

復雜的數據:

僅僅對外層修改拷貝後L改變M不變

import copy

L = [1,2,[3,4,'c','d'],'a','b']

M = copy.copy(L)

print(L)

print(M)

print(id(L))

print(id(M))

#給L追加一個元素M不會變

L.append("c")

print(L)

print(M)

print(id(L))

print(id(M))


技術分享圖片


技術分享圖片


對內層改變,那麽拷貝後都會變

import copy

L = [1,2,[3,4,'c','d'],'a','b']

M = copy.copy(L)

print(L)

print(M)

print(id(L))

print(id(M))

L[2].append("e")

print(L)

print(M)

print(id(L))

print(id(M))

技術分享圖片

技術分享圖片

這說明對內層數據的修改會改變另一個拷貝的對象

在內存中的形式為:


技術分享圖片

上圖可以看出,內層list[1,2]也是一個地址,裏面存的就是元素1,2的地址

所以對L的內層操作就是對內層list[1,2]地址的操作,這樣就會改變M

深度拷貝:

import copy

L = [1,2,[3,4,'c','d'],'a','b']

M = copy.deepcopy(L)

print(L)

print(M)

print(id(L))

print(id(M))

#給L追加一個元素M不會變

L[2].append("e")

print(L)

print(M)

print(id(L))

print(id(M))


技術分享圖片

技術分享圖片

可以看出L改變M不變

在內存中的形式:

技術分享圖片


相當於所有的都拷貝一份

1、對於復雜的數據結構copy.copy 淺拷貝 只拷貝父對象(最外一層),不會拷貝對象的內部(內層數據)的子對象。

2、copy.deepcopy 深拷貝 拷貝父對象(外層數據)及其子對象(內層數據)

3、對於基本數據類型深拷貝淺拷貝都一樣,都會產生新的數據空間

python 淺拷貝與深拷貝