1. 程式人生 > >python深淺copy探究

python深淺copy探究

是什麽 spa pre 對象修改 是把 不可變 指向 指定 動態

引入

  在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探究