python 深拷貝和淺拷貝

      在python中,當你對一個對象賦值,將其作爲參數傳遞,或者作爲結果返回時,python通常會使用指向原對象的引用(即把新對象的內存地址指向原對象),而不是真正的拷貝。其它的一些語言則在每次賦值時都都進行拷貝操作。在python中不爲賦值操作進行“隱式”的拷貝,要得到一個拷貝,必須明確的要求進行拷貝。

      所以,在python中,默認情況下對象賦值爲淺拷貝即對象引用,而深拷貝則爲真正的對象拷貝。



一,我們先來了解一下id函數,官方解釋如下:

id(object)
Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.

簡而言之,id函數就是返回對象在自己生命週期中的內存地址。下面看兩個例子:

In [48]: print id('abc')
3074738896
In [49]: cmd='abc'
In [50]: print id(cmd)
3074738896

In [51]: x='bbc'
In [52]: y='bbc'
In [54]: print id(x),id(y),id('bbc')
3052874184 3052874184 3052874184

在Python中一切皆對象,像字符串abc,數字這樣的值都是對象,只不過數字是一個整型對象,而'abc'是一個字符串對象。上面的賦值操作cmd='abc',在Python中實際的處理過程是這樣的:

先在內存中搜索是否存在字符串abc,如果字符串abc已經在內存中存在了,那就直接返回已存在的字符串abc的內存地址,讓變量cmd指向這個已存在字符串abc的內存地址。如果內存中不存在字符串abc,就先申請一段內存分配給一個字符串對象來存儲字符串abc,然後讓變量cmd去指向這個對象,實際上就是指向這段內存(這裏有點和C語言中的指針類似)。這樣做的好處,就是提升了速度。

而id(‘abc’)和id(cmd)的結果一樣,說明id函數在作用於任何對象(字符串對象或是變量對象)時,其返回的都是對象指向的內存地址。



二,淺拷貝案例:

默認情況下,我們向新對象中插入數據,則老對象也會更新(當然向原對象插入數據,新對象也會更新):

In [37]: a=[1,2,3]
In [38]: b=a
In [39]: b.append(333)
In [40]: print a
[1, 2, 3, 333]
In [41]: print b
[1, 2, 3, 333]

In [42]: print id(a),id(b)
3054610764 3054610764

結論:

我們通過id函數看到,兩個對象a,b指向同一片內存地址空間。即他們a和b對象之間的賦值操作屬於引用,不是拷貝。故修改任意一個對象,另一個對象也會隨之改變。



三,深拷貝案例

我們可以通過如下方法來解決對象引用的問題:

In [62]: import copy

In [63]: a=[1,2,3]
In [64]: b=copy.deepcopy(a)
In [65]: b.append(333)
In [66]: print a
[1, 2, 3]
In [67]: print b
[1, 2, 3, 333]
In [68]: print id(a),id(b)
3064057292 3064057644

我們需要使用copy.deepcopy方法來顯示的進行對象拷貝,這樣就不會出現前拷貝的問題。



四,判斷兩個對象是否是同一個

1,可以通過id函數來判斷

2,使用如下方式

In [72]: a=[1,2,3]
In [73]: b=a
In [74]: a is b
Out[74]: True


In [75]: a=[1,2,3]
In [76]: b=copy.deepcopy(a)
In [77]: a is b
Out[77]: False


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章