0.說明
先看看淺拷貝的概念:
淺拷貝:對一個對象進行淺拷貝其實是新建立了一個類型跟原對象一樣,其内容還是原來對象元素的引用,換句話說,這個拷貝的對象本身是新的,但是它的内容不是
序列類型對象的淺拷貝是預設類型拷貝,有以下幾種實作方式:
完全切片操作:下面操作會有
利用工廠函數:比如list()、dict()等
使用copy子產品的copy()函數
其實如果是真正了解了python對象或者說了解了可變對象和不可變對象,再根據上面的理論知識,淺拷貝和深拷貝基本上算是比較好的掌握了。是以這裡不按照書上(指的是《python核心程式設計》)的思路來進行總結,當然書上的例子作為入門也是非常不錯的。下面給出三個例子,如果都可以了解,那麼對python淺拷貝和深拷貝的掌握到這個程度也就可以了。
1.第一個例子:清單中的元素都是原子類型,即不可變對象
1
2
3
4
5
6
7
8
9
10
11
12
<code>>>> person </code><code>=</code> <code>[</code><code>'age'</code><code>, </code><code>20</code><code>]</code>
<code>>>> xpleaf </code><code>=</code> <code>person[:] </code><code>#淺拷貝</code>
<code>>>> cl </code><code>=</code> <code>list</code><code>(person) </code><code>#淺拷貝</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>person, xpleaf, cl] </code><code>#雖然是淺拷貝,但是其實也是生成了新的對象</code>
<code>[</code><code>140205544875144</code><code>, </code><code>140205544893688</code><code>, </code><code>140205544996232</code><code>]</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>person]</code>
<code>[</code><code>140205545021232</code><code>, </code><code>32419728</code><code>]</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>xpleaf]</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>cl]</code>
<code>#但是可以看到清單中的元素的還是原來對象元素的引用</code>
上面做了淺拷貝的操作,然後下面修改兩個淺拷貝的值:
<code>>>> xpleaf[</code><code>1</code><code>] </code><code>=</code> <code>22</code>
<code>>>> cl[</code><code>1</code><code>] </code><code>=</code> <code>21</code>
<code>>>> person, xpleaf, cl</code>
<code>([</code><code>'age'</code><code>, </code><code>20</code><code>], [</code><code>'age'</code><code>, </code><code>22</code><code>], [</code><code>'age'</code><code>, </code><code>21</code><code>])</code>
<code>[</code><code>140205545021232</code><code>, </code><code>32419680</code><code>]</code>
<code>[</code><code>140205545021232</code><code>, </code><code>32419704</code><code>]</code>
修改了兩個淺拷貝的值,然後發現内容并沒有互相影響,而且後來的id值也發生改變了,怎麼會這樣?不要忘了,清單中的元素都是不可變對象,修改不可變對象的值,其實就相當于是新生成了一個該對象,然後讓清單元素重新指向新生成的不可變對象,在這裡是數字對象。
了解這個例子本身并不難,但需要對python對象和序列類型本身有一定的了解。
2. 第二個例子:清單中包含容器類型變量,即可變對象
13
14
15
16
17
18
19
20
21
22
23
<code>>>> person </code><code>=</code> <code>[</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]]</code>
<code>>>> xpleaf </code><code>=</code> <code>person[:]</code>
<code>>>> cl </code><code>=</code> <code>list</code><code>(person)</code>
<code>([</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]])</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>person, xpleaf, cl]</code>
<code>[</code><code>140205544995944</code><code>, </code><code>140205544893688</code><code>, </code><code>140205544875144</code><code>]</code>
<code># 檢視大清單的元素id值</code>
<code>[</code><code>140205544996160</code><code>, </code><code>140205544875144</code><code>, </code><code>140205544996520</code><code>]</code>
<code>[</code><code>140205546176112</code><code>, </code><code>140205544995944</code><code>]</code>
<code># 檢視小清單的元素id值</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>person[</code><code>1</code><code>]]</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>xpleaf[</code><code>1</code><code>]]</code>
<code>>>> [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>cl[</code><code>1</code><code>]]</code>
三個清單的第一個元素的id值都是一樣的,這是引用傳遞,沒有什麼問題,跟第一個例子類似,是以修改這個值不會有什麼問題。但注意看第二個元素,它是一個清單,可以肯定的是,三個清單中的兩個元素的id也肯定是相同的,也是引用傳遞的道理,但現在關鍵是看第二個元素,也就是這個清單本身,三個大清單(指的是person這個清單)中的這三個小清單的id值都是一樣的,于是,淺拷貝對于對象值的影響就會展現出來了,我們嘗試去修改其中一個小清單中的值:
<code>>>> xpleaf[</code><code>1</code><code>][</code><code>1</code><code>] </code><code>=</code> <code>22</code>
<code>([</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>22</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>22</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>22</code><code>]])</code>
可以看到問題就出來了,即對一個小清單進行修改,會影響到其它的小清單。我們先抛開所謂的淺拷貝,去思考這個問題本身:有可能不會影響其它小清單嗎?肯定沒有可能的,因為三個小清單的id都一樣,三個小清單裡的元素的id也一樣,即其實這三個小清單是完全指向同一個對象的,是以,無論修改哪一個,肯定都會影響其它小清單的。
這就是所謂淺拷貝出現的問題。
3.第三個例子:使用深拷貝來解決第二個例子出現的問題
<code>>>> </code><code>from</code> <code>copy </code><code>import</code> <code>deepcopy as dcp</code>
<code>>>> cl </code><code>=</code> <code>dcp(person)</code>
<code>[</code><code>140205546176112</code><code>, </code><code>140205544996520</code><code>]</code>
<code>[</code><code>140205546176112</code><code>, </code><code>140205544571320</code><code>]</code>
可以看到雖然是進行了深拷貝,但發現跟前面的其實并沒有什麼不同,下面我們再來修改其中一個小清單:
<code>([</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>22</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>22</code><code>]], [</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]])</code>
此時可以看到,cl的小清單的第二個元素的id跟原來是一樣的,但是xpleaf和person的小清單元素的id發生了改變,同時值也是我們修改的那樣。那是因為xpleaf是person的淺拷貝,但是cl是person的深拷貝。
這就是所謂的深拷貝。
4.第四個例子:檢驗
其實隻要了解了上面三個例子(這意味着對python對象本身和序列類型本身也有比較深刻的了解),是以的淺拷貝和深拷貝也不是什麼問題了。
至于是否明白,可以參考下面這個例子:
<code>>>> person </code><code>=</code> <code>[</code><code>'name'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>1</code><code>, </code><code>2</code><code>])]</code>
<code>>>> </code>
<code>>>> xpleaf[</code><code>0</code><code>] </code><code>=</code> <code>'xpleaf'</code>
<code>>>> cl[</code><code>0</code><code>] </code><code>=</code> <code>'cl'</code>
<code>([</code><code>'name'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>1</code><code>, </code><code>2</code><code>])], [</code><code>'xpleaf'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>1</code><code>, </code><code>2</code><code>])], [</code><code>'cl'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>1</code><code>, </code><code>2</code><code>])])</code>
<code>>>> xpleaf[</code><code>1</code><code>][</code><code>1</code><code>][</code><code>0</code><code>] </code><code>=</code> <code>'clyyh'</code>
<code>([</code><code>'name'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>'clyyh'</code><code>, </code><code>2</code><code>])], [</code><code>'xpleaf'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>'clyyh'</code><code>, </code><code>2</code><code>])], [</code><code>'cl'</code><code>, (</code><code>'hobby'</code><code>, [</code><code>1</code><code>, </code><code>2</code><code>])])</code>
如果對這個例子的輸出覺得完全沒有問題的,那麼也就ok了!
當然,肯定還有遺漏的地方,還望指出。