python深淺copy探究
引入
在python程序中,如果我們操作一個變量的值去做運算,而又想在下次調用時,仍使用原來的變量的值去做運算,那麽我們我們就需要將這個變量去做備份,這就是本文所要探究的問題。
開始
變量-對象-引用:
python中全部皆對象,Python中變量是指對象(甚至連type其本身都是對象,type對象)的引用,Python是動態類型,程序運行時候,會根據對象的類型來確認變量到底是什麽類型。
我們有時候會見到這樣一種情況:
a = 1
b = a
這樣做不就是把數據copy了一份嗎,錯,這樣做只是在程序中新創建了一個對象b,去引對象a創建是指定的值,也就是說,它們是指向了同一塊內存地址,而不是在創建 b = a 時又重新在內存中開辟出一塊空間來,所以當一個變量的值被修改,則另一個變量的值也會隨之被修改,這樣說可能不太理解,來個圖示吧:
這個叫做"共享引用",而不是做一個副本(不要犯這樣的錯哦)。
正題
現在就開始探究一下深淺copy
深淺copy的方法由python內置的一標準庫提供(提供的copy方法,適合所有類型對象)
簡單點說
- copy.copy 淺拷貝 只拷貝父對象,不會拷貝對象的內部的子對象。
- copy.deepcopy 深拷貝 拷貝對象及其子對象
用一個簡單的例子來說明一下
>>> import copy >>> a = [1,2,3,[‘a‘,‘b‘,‘c‘]] >>> b = a >>> c = copy.copy(a)>>> d = copy.deepcopy(a)
a是一個列表,表中的a[3]也是一個列表(也就是一個內部的子對象),b是對a列表的又一個引用,所有a,b是完全相同的,我們可以通過id(a)來驗證。
>>> id(a) 60356208 >>> id(b) 60356208 >>> id(c) 63132896 >>> id(d) 63133256
a 和 b的相同也證實了前面所說的共享引用;
深淺copy的區別:
淺copy
>>> import copy>>> a = [1,2,3,[‘a‘,‘b‘,‘c‘]] #a具有兩級對象的列表 >>> b = copy.copy(a) #創建變量b,使其淺copy a的值 >>> b [1, 2, 3, [‘a‘, ‘b‘, ‘c‘]] >>> a[1] = "two" #當a的父對象修改之後而b的父對象不會被修改 >>> a [1, ‘two‘, 3, [‘a‘, ‘b‘, ‘c‘]] >>> b [1, 2, 3, [‘a‘, ‘b‘, ‘c‘]] >>> a[3][0] = ‘A‘ #當a的子對象被修改之後b的子對象也會隨之修改 >>> a [1, ‘two‘, 3, [‘A‘, ‘b‘, ‘c‘]] >>> b [1, 2, 3, [‘A‘, ‘b‘, ‘c‘]]
深copy
>>> import copy >>> a = [1,2,3,[‘a‘,‘b‘,‘c‘]] #a具有兩級對象的列表 >>> b = copy.copy(a) #創建變量b,使其深copy a的值 >>> b [1, 2, 3, [‘a‘, ‘b‘, ‘c‘]] >>> a[1] = "two" #當a的父對象修改之後而b的父對象不會被修改 >>> a [1, ‘two‘, 3, [‘a‘, ‘b‘, ‘c‘]] >>> b [1, 2, 3, [‘a‘, ‘b‘, ‘c‘]] >>> a[3][0] = ‘A‘ #當a的子對象被修改之後b的子對象仍不會隨之修改 >>> a [1, ‘two‘, 3, [‘A‘, ‘b‘, ‘c‘]] >>> b [1, 2, 3, [‘a‘, ‘b‘, ‘c‘]]
淺拷貝是指拷貝的只是原對象元素的引用,換句話說,淺拷貝產生的對象本身是新的,但是它的內容不是新的,只是對原對象的一個引用
>>> aList=[[1, 2], 3, 4] >>> bList = aList[:] #利用切片完成一次淺拷貝 >>> id(aList) 3084416588L >>> id(bList) 3084418156L >>> aList[0][0] = 5 >>> aList [[5, 2], 3, 4] >>> bList [[5, 2], 3, 4]
但是有點需要特別提醒的,如果對象本身是不可變的,那麽淺拷貝時也會產生兩個值
>>> aList = [1, 2] >>> bList = aList[:] >>> bList [1, 2] >>> aList [1, 2] >>> aList[1]=111 >>> aList [1, 111] >>> bList [1, 2]
為什麽bList的第二個元素沒有變成111呢?因為數字在python中是不可變類型!!
在這順便回顧下Python標準類型的分類:
- 可變類型: 列表,字典
- 不可變類型:數字,字符串,元組
理解了淺拷貝,深拷貝是什麽自然就很清楚了。
python中有一個模塊copy,deepcopy函數用於深拷貝,copy函數用於淺拷貝。
最後,對象的賦值是深拷貝還是淺拷貝?
對象賦值實際上是簡單的對象引用
>>> a = 1 >>> id(a) 135720760 >>> b = a >>> id(b) 135720760
a和b完全是一回事。
python深淺copy探究