天天看點

Python進階:細說Python淺拷貝和深拷貝

0.說明 

        先看看淺拷貝的概念:

淺拷貝:對一個對象進行淺拷貝其實是新建立了一個類型跟原對象一樣,其内容還是原來對象元素的引用,換句話說,這個拷貝的對象本身是新的,但是它的内容不是

        序列類型對象的淺拷貝是預設類型拷貝,有以下幾種實作方式:

完全切片操作:下面操作會有

利用工廠函數:比如list()、dict()等

使用copy子產品的copy()函數

        其實如果是真正了解了python對象或者說了解了可變對象和不可變對象,再根據上面的理論知識,淺拷貝和深拷貝基本上算是比較好的掌握了。是以這裡不按照書上(指的是《python核心程式設計》)的思路來進行總結,當然書上的例子作為入門也是非常不錯的。下面給出三個例子,如果都可以了解,那麼對python淺拷貝和深拷貝的掌握到這個程度也就可以了。

1.第一個例子:清單中的元素都是原子類型,即不可變對象

1

2

3

4

5

6

7

8

9

10

11

12

<code>&gt;&gt;&gt; person </code><code>=</code> <code>[</code><code>'age'</code><code>, </code><code>20</code><code>]</code>

<code>&gt;&gt;&gt; xpleaf </code><code>=</code> <code>person[:]  </code><code>#淺拷貝</code>

<code>&gt;&gt;&gt; cl </code><code>=</code> <code>list</code><code>(person)      </code><code>#淺拷貝</code>

<code>&gt;&gt;&gt; [</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>&gt;&gt;&gt; [</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>&gt;&gt;&gt; [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>xpleaf]</code>

<code>&gt;&gt;&gt; [</code><code>id</code><code>(x) </code><code>for</code> <code>x </code><code>in</code> <code>cl]</code>

<code>#但是可以看到清單中的元素的還是原來對象元素的引用</code>

        上面做了淺拷貝的操作,然後下面修改兩個淺拷貝的值:

<code>&gt;&gt;&gt; xpleaf[</code><code>1</code><code>] </code><code>=</code> <code>22</code>

<code>&gt;&gt;&gt; cl[</code><code>1</code><code>] </code><code>=</code> <code>21</code>

<code>&gt;&gt;&gt; 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>&gt;&gt;&gt; person </code><code>=</code> <code>[</code><code>'name'</code><code>, [</code><code>'age'</code><code>, </code><code>20</code><code>]]</code>

<code>&gt;&gt;&gt; xpleaf </code><code>=</code> <code>person[:]</code>

<code>&gt;&gt;&gt; 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>&gt;&gt;&gt; [</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>&gt;&gt;&gt; [</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>&gt;&gt;&gt; [</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>&gt;&gt;&gt; [</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>&gt;&gt;&gt; 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>&gt;&gt;&gt; </code><code>from</code> <code>copy </code><code>import</code> <code>deepcopy as dcp</code>

<code>&gt;&gt;&gt; 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>&gt;&gt;&gt; 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>&gt;&gt;&gt; </code>

<code>&gt;&gt;&gt; xpleaf[</code><code>0</code><code>] </code><code>=</code> <code>'xpleaf'</code>

<code>&gt;&gt;&gt; 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>&gt;&gt;&gt; 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了!

        當然,肯定還有遺漏的地方,還望指出。