Python中copy,deepcopy,=之深拷貝淺拷貝使用詳解
阿新 • • 發佈:2019-02-20
python中對於物件的拷貝分為淺拷貝(copy)和深拷貝(deepcopy)兩種方式。其中淺拷貝由“=”完成。而深拷貝由copy模組中deepcopy()函式擔任。
淺拷貝和深拷貝的區別是:淺拷貝只是將原物件在記憶體中引用地址拷貝過來了。讓新的物件指向這個地址。而深拷貝是將這個物件的所有內容遍歷拷貝過來了,相當於跟原來沒關係了,所以如果你這時候修改原來物件的值跟他沒關係了,不會隨之更改。
1.淺拷貝"="的使用
#1.使用=複製不可變物件的值,以及複製以後修改其值後的變化。 val1 = 1000 val2 = val1 print("val1 is :{0},val2 is :{1}".format(val1,val2))#val1 is :1000,val2 is :1000 print(id(val1),id(val2)) #34052192 34052192 #這時候修改val1的值,儘管val2指向val1.但因為val1是不可變型別,修改其值,會重新給新值分配記憶體,然後指向他。 val1 += 1 print(val1,id(val1),val2,id(val2)) #1001 10131616 1000 10131568 值不一樣,記憶體地址也不一樣了 #1.使用=複製可變物件的值,以及複製以後修改其值後的變化。 ls1 =[1,2,3,4] ls2 = ls1 print(id(ls1),id(ls2)) #43702792 43702792 直接使用=複製變數,記憶體地址一樣,值也一樣。 print(ls1,ls2) #[1, 2, 3, 4] [1, 2, 3, 4]直接使用=複製變數,記憶體地址一樣,值也一樣。 #這時候修改可變對的值,因為其值可變,所以只需要在原記憶體地址上修改即可。 ls1.append(5) print(id(ls1),id(ls2)) #可變物件修改其值,記憶體引用不變 print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4, 5] 因為兩個變數的記憶體指向一樣,所以值也一樣。
2.深拷貝:copy.deepcopy()函式
#1.使用copy.deepcopy()拷貝不可變物件的值,以及複製以後修改其值後的變化。 val1 = 1000 val2 = copy.deepcopy(val1) print("val1 is :{0},val2 is :{1}".format(val1,val2))#val1 is :1000,val2 is :1000 print(id(val1),id(val2)) #33717408 33717408 對於不可變物件,深度拷貝記憶體地址沒有修改。 val1 += 1 print(val1,id(val1),val2,id(val2)) #1001 33717904 1000 33717408 #1.使用copy.deepcopy()複製可變物件的值,以及複製以後修改其值後的變化。 ls1 =[1,2,3,4] ls2 = copy.deepcopy(ls1) print(id(ls1),id(ls2)) #34628472 34628712 注意對於可變物件深度拷貝後記憶體地址都修改了。 print(ls1,ls2) #[1, 2, 3, 4] [1, 2, 3, 4] ls1.append(5) print(id(ls1),id(ls2)) #34628472 34628712 print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4] #注意這個時候ls2的值沒有隨著ls1修改。
總結:其實對於淺拷貝和深拷貝來說,如果拷貝物件都是不可變物件的話,那麼兩者效果是一樣的。如果是可變物件的話,“=”拷貝的方式,只是拷貝了記憶體中的地址引用,兩個物件的地址引用一樣,所以兩個物件的值會隨著一方的修改而修改。而對於deepcopy()來說,如果是可變物件的話,那麼拷貝內容後新物件的記憶體地址也會重新分配,跟原來的記憶體地址不一樣了。所以兩者任意修改變數的內容不會對另一方造成影響。
3.注意一個特殊的copy(),跟深淺拷貝都有區別,慎用。
1.使用copy()拷貝不可變物件 val1 = 1000 val2 = copy.copy(val1) print(val1,val2)##1000 1000 print(id(val1),id(val2))#8551568 8551568 2.使用copy()拷貝可變物件 ls1 =[1,2,3,4] ls2 = copy.copy(ls1) ls1.append(5) print(ls1,ls2) #[1, 2, 3, 4, 5] [1, 2, 3, 4] 看上去copy()函式效果和deepcopy()效果一樣,可變物件拷貝後值也沒有隨著一個物件的修改而修改。 然後真實情況真是這樣嘛?請看下面的案例,同樣是拷貝可變物件。 origin = [1, 2, [3, 4]] cop1 = copy.copy(origin) cop2 = copy.deepcopy(origin) origin[2][0] = "hey!" #修改資料來源的值 print(cop1,cop2) #[1, 2, ['hey!', 4]] [1, 2, [3, 4]] 很顯然這時copy()函式拷貝的值隨著原物件的值修改了,而deepcopy()的值沒有隨著原物件的值修改。 主要是因為deepcopy會將複雜物件的每一層複製一個單獨的個體出來對於copy()函式要慎用,慎用。