Python中深拷貝與淺拷貝詳解

所有Python對象都有三個屬性:身份、類型、值

name='a'
id(name)		#id-身份唯一標識
type(name)	#對象類型

1.可變對象

列表、字典、集合,指可變對象的值可變,身份不變

2.不可變對象

數字、字符串、元組對象身份和值都不可變。新創建對象被關聯到原來變量名,舊對象被丟棄,垃圾回收器會在適當時機回收這些對象

3.引用

Python程序中每個對象都會在內存區域中申請一塊空間來保存,該對象在內存中所在位置地址被稱爲引用。開發程序時所定義的變量名實際是對象地址引用,引用是內存中的一個數字地址編號,使用對象時只要知道該對象的地址,就可操作這個對象,但因爲數字地址不方便在開發時使用和記憶,所以使用變量名形式來代替對象數字地址。Python中變量就是地址的一種表示形式,並不新開闢存儲空間

就像IP地址,訪問網站時實際都是通過IP地址確定主機,而IP地址不方便記憶,所以使用域名代替IP地址,使用域名訪問網站時被解析成IP地址使用

age=18
id(age)
Out: 1730306752
id(18)
Out: 1730306752

賦值的本質是讓多個變量同時引用同一個對象的地址

4.淺拷貝

只拷貝父對象,不拷貝對象內部中的子對象

不可變對象:

不可變對象只在修改時纔會在內存中開闢新空間,而拷貝實際上是讓多個對象同時指向一個引用,和對象賦值沒區別

import copy
a=10
b=copy.copy(a)

id(a)
Out:1730306496
id(b)
Out:1730306496

可變對象:

可變對象拷貝會在內存中開闢一個新空間來保存拷貝數據。當再改變之前對象時,對拷貝之後的對象沒有任何影響

import copy
l1=[1,2,3]
l2=copy.copy(l1)		#l2=l1[:] 利用切片完成淺拷貝

id(l1)
Out:1916631742088

id(l2)
Out:1916636282952

l1[0]=11			#數字爲不可變對象

id(l1)
Out:1916631742088
id(l2)
Out:1916636282952

l1		#[11,2,3]
l2		#[1,2,3]





l1=[1,2,3]
l2=l1

id(l1)
Out: 1916633584008
id(l2)
Out: 1916633584008

l1[0]=11

id(l1)
Out: 1916633584008
id(l2)
Out: 1916633584008

print(l1,l2)			#[11,2,3] [11,2,3]

複雜對象在拷貝時並沒有解決數據在傳遞之後的數據改變問題。原因是copy函數在拷貝對象時只是將指定對象的所有引用拷貝一份,如果這些引用當中包含一個可變對象(如列表),那麼數據還是會被改變。這種拷貝方式稱爲淺拷貝

a=[1,2]
l1=[3,4,a]
l2=copy.copy(l1)
id(l1)
Out:1916631704520
id(l2)
Out:1916631713736

a[0]=11
id(l1)
Out:1916631704520
id(l2)
Out:1916631713736

l1
Out:[3,4,[11,2]]
l2
Out:[3,4,[11,2]]

5.深拷貝

區別於淺拷貝只拷貝頂層引用,深拷貝會逐層進行拷貝,直到拷貝的所有引用都是不可變引用爲止(拷貝對象及其子對象)

import copy
a=[1,2]
l1=[3,4,a]
l2=copy.deepcopy(l1)

id(l1)
Out:1916632194312
id(l2)
Out:1916634281416

a[0]=11
id(l1)
Out:1916632194312
id(l2)
Out:1916634281416

l1
Out:[3,4,[11,2]]

l2
Out:[3,4,[1,2]]

6.淺拷貝優勢

1.時間角度:淺拷貝花費時間更少

2.空間角度:淺拷貝花費內存更少

3.效率角度:淺拷貝只拷貝頂層數據,一般情況下比深拷貝效率高

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章