深淺拷貝的原理python
深淺拷貝用法來自copy模塊。服務器
導入模塊:import copyspa
淺拷貝:copy.copycode
深拷貝:copy.deepcopyblog
字面理解:淺拷貝指僅僅拷貝數據集合的第一層數據,深拷貝指拷貝數據集合的全部層。因此對於只有一層的數據集合來講深淺拷貝的意義是同樣的,好比字符串,數字,還有僅僅一層的字典、列表、元祖等.索引
對於如下數據深淺拷貝的意義是同樣的(由於數據類型中只有一層):內存
name = 'beijing' #字符串 age = 12 #數字 list1 = [1,2,3,4] #列表 dic1 = {'name':'beijing','age':20} #字典
從內存地址來理解深淺拷貝:字符串
>>> import copy >>> name="hahah" #字符串 >>> name1=copy.copy(name) >>> >>> name2=copy.deepcopy(name) >>> print(id(name),id(name1),id(name2)) 11577192 11577192 11577192 >>> sum=111 #數字 >>> sum1=copy.copy(sum) >>> >>> sum2=copy.deepcopy(sum) >>> print(id(sum),id(sum1),id(sum2)) 503865568 503865568 503865568
如上圖,對於數字和字符串的深淺拷貝都只是將變量的索引指向了原來的內存地址,例如在sum,sum1,sum2三個變量中,不管修改任意其中一個變量,只是將其指向了另外一個內存地址,其餘兩個變量不會變,字符串同理。所以,對於 數字 和 字符串 而言,賦值、淺拷貝和深拷貝無心義,由於其永遠指向同一個內存地址。模板
字典(列表)的深淺拷貝class
賦值:
import copy n1 = {'k1':'wu','k2':123,'k3':['alex',678]} n2 = n1
淺拷貝:
import copy n1 = {'k1':'wu','k2':123,'k3':['alex',678]} n3 = copy.copy(n1)
深拷貝:
import copy n1 = {'k1':'wu','k2':123,'k3':['alex',678]} n4 = copy.deepcopy(n1)
深淺拷貝的應用場景
好比在CMDB系統中,咱們定義了一個報警模版call給全部的服務器使用,此時有一批特殊應用的服務器須要不通的報警參數,咱們既不想單獨新建模版來一個一個添加報警參數,又不想修改默認模版而影響其餘機器的報警閾值。此時咱們就須要用深拷貝來完成。示例以下:
默認模版:
call = { 'cpu':80, 'mem':80, 'disk':80 }
此時的特殊模版需求是cpu報警閥值要改爲75,而不影響默認模版使用
代碼以下:
import copy #默認模版 call = { 'cpu':[80,], 'mem':[80,], 'disk':[80,] } #新模板 new_call = copy.deepcopy(call) #修改新模版 new_call['cpu'] = 75 #查看新舊模版的值 print('新的模版爲:%s' %(new_call)) print('默認模版爲:%s' %(call)) #打印結果: #新的模版爲:{'mem': 80, 'disk': 80, 'cpu': 75} #默認模版爲:{'mem': 80, 'disk': 80, 'cpu': 80} #上面的代碼顯示咱們只改了新的模版,而默認模版並無修改,而且咱們用了copy而不是單獨新建模版。
假設咱們用淺copy來作結果是這樣的:
import copy #默認模版 call = { 'cpu':[80,], 'mem':[80,], 'disk':[80,] } #新模板 new_call = copy.copy(call) #修改新模版 new_call['cpu'] = 75 #查看新舊模版的值 print('新的模版爲:%s' %(new_call)) print('默認模版爲:%s' %(call)) #打印的結果: #新的模版爲:{'mem': [80], 'disk': [80], 'cpu': [75]} #默認模版爲:{'mem': [80], 'disk': [80], 'cpu': [75]} #默認模版和新模版都被修改了,顯然這不是咱們要的結果
分析緣由:深拷貝的時候python將字典的全部數據在內存中新建了一份,因此若是你修改新的模版的時候老模版不會變。相反,在淺copy 的時候,python僅僅將最外層的內容在內存中新建了一份出來,字典第二層的列表並無在內存中新建,因此你修改了新模版,默認模版也被修改了。