標籤: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、對於基礎資料型別 (Elementary Data Type)深拷貝淺拷貝都一樣,都會產生新的資料空間
python 淺拷貝與深拷貝