Python自學指南---基礎篇(七)深拷貝與淺拷貝

關鍵知識點:深、淺拷貝
講到這裏需要提到python中一個重要的知識點,就是深、淺拷貝。深、淺拷貝的問題一般涉及的都是容器對象

首先說淺拷貝,所謂的淺拷貝就是:1、創建一個與原來類型相同的新對象。2、其中的內容是原來對象元素的引用。其中第2點就體現了淺拷貝中的“淺”,換一種說法就是,新容器內部裝的對象就是原容器內部的對象。

實現淺拷貝的方法有三種:

  1. 完全切片操作[:]
  2. list(), tuple(), dict()等工廠函數
  3. copy模塊中的copy()方法

舉一個淺拷貝的例子,有一批學生利用list記錄自己一個學期考試的成績,比如這學期考了三次試,那麼Alice就可以利用一個嵌套的list進行記錄:

>>> Alice = ['Alice', [89, 78, 100]]  #記錄自己的名字,和三次考試成績
>>> Alice
['Alice', [89, 78, 100]]

然後Bob沒有選擇新建一個list,而是使用[:] 複製了Alice的list,並且做了修改:

>>> Bob = Alice[:] #記錄自己的名字,和三次考試成績
>>> Bob[0] = 'Bob'    #修改名字
>>> Bob[1][0] = 91    #修改成績
>>> Bob[1][1] = 71
>>> Bob[1][2] = 80
>>> Bob
['Bob', [91, 71, 80]]

然後,再看Alice的list:

>>> Alice
['Alice', [91, 71, 80]]

可以發現:
1、Alice的list中,名字沒有被修改,這是因爲淺拷貝是“創建一個與原來類型相同的新對象”,也就是說id(Alice)!=id(Bob)

>>> id(Alice)
4353353704
>>> id(Bob)
4353353488

因此Bob[0] = 'Bob' 改變的是Bob這個list對象(注意沒有改變Bob[0]指向的對象,而是直接將Bob[0]指向了新對象),而不會對Alice這個list有任何影響。

2、Alice的list中,成績都被修改了。這就是因爲淺拷貝創建的對象,其中的內容是原來對象元素的引用,也就是說id(Alice[i]) = id(Bob[i])

>>> id(Alice[1])
4353228672
>>> id(Bob[1])
4353228672

那麼,Bob[1][0] = 91 改變的就是Bob[1]指向的對象,同時也是Alice[1]指向的對象。

如果使用深拷貝,那麼新對象的特點就是:對於新對象內的任意一個子對象,如果是可變對象,或內部嵌套可變對象,那麼該子對象一定不會與原對象內部的對應對象相同;反之則相同,以節省內存。這樣就保證改變新對象時不會影響原對象。

利用copy模塊的deepcopy()可以實現深拷貝:

>>> Alice = ['Alice', [89, 78, 100]]
>>> Bob = copy.deepcopy(ALice)
>>>> [id(x) for x in Alice]
[4353348880, 4353353776]
>>> [id(x) for x in Bob]
[4353348880, 4353355360]

由於字符串是不可變對象,因此即使執行深拷貝也不會創建新對象,而list就會創建新的對象。

再看一些例子:

>>> Alice = ['Alice', (89, 78, 100)]
>>> Bob = copy.deepcopy(Alice)
>>> id(Bob[1])
4353371504
>>> id(Alice[1])
4353371504

>>> Alice = ['Alice', ([89,90], 78, 100)]
>>> Bob = copy.deepcopy(Alice)
>>> id(Bob[1])
4353371664
>>> id(Alice[1])
4353368144
>>> id(Bob[1][0])
4353353560
>>> id(Alice[1][0])
4353355570

可以看出,如果tuple內部還會嵌套list,那麼tuple就可以被視爲“可變的”,那麼進行深拷貝的時候,對應就會創建一個新的tuple,內部的list由於是可變的所以也會新建。

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