天天看點

一入python深似海--淺拷貝與深拷貝

python中有一個子產品copy,deepcopy函數用于深拷貝,copy函數用于淺拷貝。要了解淺拷貝,必須先弄清楚python中的引用。

引用

Python中一切都是對象,變量中存放的是對象的引用。這是一個普遍的法則。可以說 Python 沒有指派,隻有引用。如,a=1,變量a隻是整數對象1的引用。

可變對象與不可變對象及其引用

一、不可變對象

不可變對象包括:數字,字元串,元組。 由于Python中的變量存放的是對象引用,是以對于不可變對象而言,盡管對象本身不可變,但變量的對象引用是可變的。運用這樣的機制,有時候會讓人産生糊塗,似乎可變對象變化了。如下面的代碼:

i=73
i+=2
           

這裡的‘=’表示引用。

一入python深似海--淺拷貝與深拷貝

從上面得知,不可變的對象的特征沒有變,依然是不可變對象,變的隻是建立了新對象,改變了變量的對象引用。

二、可變對象

可變對象包括:清單、字典 其對象的内容是可以變化的。當對象的内容發生變化時,變量的對象引用是不會變化的。如下面的例子。

m=[5,9]
m+=[6]
           

清單m的每個元素均是對象的引用。對象的生成,涉及到對應機制,如整形對象分為大整數對象和小整數對象,生成機制不同,這裡不作詳細闡述。

一入python深似海--淺拷貝與深拷貝

三、函數的參數傳遞

函數的參數傳遞,本質上傳遞的是引用。

拷貝

(1)沒有限制條件的分片表達式(L[:])能夠複制序列,但此法隻能淺層複制。

(2)字典 copy 方法,D.copy() 能夠複制字典,但此法隻能淺層複制

(3)有些内置函數,例如 list,能夠生成拷貝 list(L)

(4)copy 标準庫子產品能夠生成完整拷貝:deepcopy,遞歸 copy

淺拷貝

淺拷貝由copy子產品中的copy()函數實作,簡單地說,copy.copy 淺拷貝 隻拷貝父對象,不會拷貝對象的内部的可變子對象。具體點說就是,淺拷貝是指拷貝的隻是原對象元素的引用,換句話說,淺拷貝産生的對象本身是新的,但是它的内容不是新的,隻是對原子對象的一個引用。

import copy
aList=[[1,2],3,4]
bList=copy.copy(aList)
print aList
print bList

print id(aList)
print id(bList)

aList[0][0]=5

print aList
print bList
           

由id(aList)不等于id(bList),表明淺拷貝産生的對象本身是新的,但是它的子對象(即,那個清單)是對原子對象的一個引用。 那麼3,4兩個元素呢?這就要講講python中的可變對象和不可變對象的引用了。

但是有點需要特别提醒的,如果對象本身是不可變的,那麼淺拷貝時也是引用。 見這個例子:

import copy
aList=[[1,2],3,4]
bList=copy.copy(aList)
print aList
print bList

print id(aList[1])
print id(bList[1])

aList[2]=5#變量的對象引用改變了而已
aList[0]=[0,1,1]#變量的對象引用改變了而已

print aList
print bList
           

總結,即 淺拷貝産生的對象本身是新的,但是它的内容不是新的, 隻是對原 子對象 的一個 引用。

深拷貝

淺拷貝由copy子產品中的deepcopy()函數實作,簡單地說,深拷貝 拷貝對象及其子對象。

一個例子展示引用、深拷貝與淺拷貝的不同。

import copy
aList=[[1,2],3,4]
bList=aList
cList=copy.copy(aList)
dList=copy.deepcopy(aList)
print aList
print bList
print cList
print dList
print id(aList)
print id(bList)
print id(cList)
print id(dList)
aList.append(5)
aList[0].append('hello')

print aList
print bList
print cList
print dList
           

其實我覺得記住這一點就行,淺拷貝産生的對象本身是新的,但是它的内容不是新的,隻是對原子對象的一個引用。關鍵是要了解python中引用的含義。