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

python 淺拷貝和深拷貝淺析

編碼過程中發現,列表a和b,初始化a,b拷貝a,b中元素值改過之後,a中元素也會跟著修改,一直以為是自己程式碼邏輯出了錯誤,最後發現這裡的坑是python中淺拷貝和深拷貝的機制


在python中,物件的屬性值有:物件id(記憶體地址),物件型別,物件值

id:唯一標識一個物件:if a is b的判斷方式
Type:標識物件的型別
Value:物件的值:if a ==b的判斷方式

一、賦值

python中,賦值a=b,實際上是b拷貝了a的引用,這裡“=”只是把a物件的引用傳遞給b物件而已,原始列表改變,b也會改變,因為a和b都是對原始列表的引用

如下:b = a ,物件a賦值給b,這裡面a和b指向的就是同一個物件,a和b只不過是這個物件的兩個引用而已,共享一個物件

a = ['str',1,2,3,4,5]
b = a
a[0] = 'sss'
a[1] = 10
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print a,b
111594624 111594624
110736892 110736892
['sss', 10, 2, 3, 4, 5] ['sss', 10, 2, 3, 4, 5]

二、淺拷貝(shallow copy)

淺拷貝:import copy

如下可以看到與上述賦值是不同的,淺拷貝產生新的物件,但是子物件不拷貝;

a中物件值修改之後,id是變化的,修改值之後不會影響原來的值,但是如果物件中有子物件(如下a[6]是個list),並且是可變物件,id是不變的,修改子物件會同步修改原來的值,即共享子物件

import copy
a = ['str',1,2,3,4,5,[6,7]]
b = copy.copy(a)
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[0] = 'sss'
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[1] = 10
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[6][0] = 666
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
112149136 112149136
112572008 112572008
112571948 112571948
['str', 1, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
113793120 112149136
112572008 112572008
112571948 112571948
['sss', 1, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
113793120 112149136
112571900 112572008
112571948 112571948
['sss', 10, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
113793120 112149136
112571900 112572008
113722716 113722716
['sss', 10, 2, 3, 4, 5, [666, 7]] ['str', 1, 2, 3, 4, 5, [666, 7]]
   

注:類似於[0,0,0]*4這樣的二維陣列,也是淺拷貝的一種,多維陣列初始化推薦如下迴圈方法

list=[[0 for t in range(2)]for i in range(3)]
print list
list[0][1] = 2
print list
[[0, 0], [0, 0], [0, 0]]
[[0, 2], [0, 0], [0, 0]]

三、深拷貝

深拷貝:import copy

拷貝產生新的物件,包含子物件的拷貝,是個完全新的物件

a中物件值修改之後,id是變化的,修改值之後不會影響原來的值,即便物件中有子物件(如下a[6]是個list),並且是可變物件,id是不變的,修改子物件也不會影響原來的值!

import copy
a = ['str',1,2,3,4,5,[6,7]]
b = copy.deepcopy(a)
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6]),id(b[6])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[0] = 'sss'
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6]),id(b[6])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[1] = 10
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6]),id(b[6])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
a[6][0] = 666
print id(a[0]),id(b[0])
print id(a[1]),id(b[1])
print id(a[6]),id(b[6])
print id(a[6][0]),id(b[6][0])
print a,b
print '   '
38093456 38093456
38516328 38516328
111663624 111724384
38516268 38516268
['str', 1, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
112106096 38093456
38516328 38516328
111663624 111724384
38516268 38516268
['sss', 1, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
112106096 38093456
38516220 38516328
111663624 111724384
38516268 38516268
['sss', 10, 2, 3, 4, 5, [6, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]
   
112106096 38093456
38516220 38516328
111663624 111724384
112018780 38516268
['sss', 10, 2, 3, 4, 5, [666, 7]] ['str', 1, 2, 3, 4, 5, [6, 7]]