Python中的Copy和Deepcopy


一,Python的對象:

  Python存在大量的對象,我們一般提到的對象都是C中的結構體在堆中申請的一塊內存(以CPython為例),每一個對象都有ID,可以通過ID(Object)獲得。對象的范圍包括內建類型的對象(如int類型的對象123,str的對象"test",list的對象[],生成器對象等等)、用戶自建類型的對象、函數(lambda函數,生成器函數)、類型、Ture、False(bool類型的對象)、None(NoneType的對象)。

 1 print id(123)
 2 print id("test")
 3 print id([])
 4 print id(xrange(1, 3))
 5 print id(lambda v: v)
 6 print id(int)
 7 print id(True)
 8 print id(None)
 9 
10 print type(123)
11 print type("test")
12 print type([])
13 print type(xrange(1, 3))
14 print type(lambda v: v)
15 print type(int)
16 print type(True)
17 print type(None)
 1 19257680
 2 19062656
 3 27888896
 4 19590176
 5 27863344
 6 505361888
 7 505379788
 8 505354444
 9 <type 'int'>
10 <type 'str'>
11 <type 'list'>
12 <type 'xrange'>
13 <type 'function'>
14 <type 'type'>
15 <type 'bool'>
16 <type 'NoneType'>

  猜想int類型、True和None都是在高地址中,而動態生成的都是位於低地址中。

 

二,Python的引用計數:

  所有對象都采用引用計數,給對象分配新名詞或者將其放入容器中,這個對象的引用計數都會增加。當離開作用域或者被重新賦值的時候,這個對象的引用計數就會減少。當減少為0,垃圾收集器會將其銷毀。

  Python中的對象分為immutable和mutabel,作為immutable的int、char和tuple,相同的值在內存中只會生成一次,每次將其賦值到變量中,便會增加一個引用計數。而作為mutable的list、dict、xrange(生成器)和lambda(函數),每次生成都會在內存中生成一個新的對象。

  另外:傳參的時候,若參數為mutable,則傳的是引用,若參數為immutable,則傳的是值。

 1 a = 123     #創建一個值為123的對象
 2 b = 123     #增加123的引用計數
 3 a = 111     #創建一個值為111的對象,減少123的引用計數
 4 b = a       #增加111的引用計數
 5 
 6 c = []      #創建一個空隊列
 7 d = []      #創建一個新的空隊列
 8 c = []      #再創建一個新的空隊列,減少原隊列的引用計數
 9 c = d       #增加d隊列的引用計數,減少c隊列的引用計數
10 c.append(1) #創建一個值為1的對象,不改變原隊列的引用計數

 

三,Shallow copy和Deep copy的區別

  Python document中是這么說的:

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original. 

  這其中的區別就是淺復制會簡單的復制引用,不管他是mutable還是immutable。而深復制則會遞歸地復制immutable對象引用,對於mutable,則會新建一個對象。

1 import copy
2 a = [1, 2]
3 b = [a, 3]
4 c = copy.copy(b)        #c = [[1, 2], 3]
5 d = copy.deepcopy(b)    #d = [[1, 2], 3]
6 a.append(3)             #c = [[1, 2, 3], 3]
7                         #d = [[1, 2], 3]

 

四,如何控制Shallow copy和Deep copy?

  在deepcopy時候,會遇到問題,比如有對象中有一個指向用戶信息的列表,用戶希望在復制的時候直接引用原列表。這個時候可以使用定制功能。

  可以在類型中定義__copy__和__deepcopy__實現shallow copy和deep copy,當用戶下次調用copy.copy和copy.deepcopy時,便會調用__copy__和__deepcopy__。

 1 import copy
 2 class Example(dict):
 3     def __init__(self, needcopy={}, userinfo={}):
 4         super(Example, self).__init__()
 5         self.need = needcopy
 6         self.user = userinfo
 7 
 8     def __deepcopy__(self, memo):
 9         if memo is None:
10             memo = {}
11         result = self.__class__()
12         memo[id(self)] = result
13         for key in self.need.keys():
14             result.need = copy.deepcopy(self.need)
15             result.user = self.user
16         return result
17 
18 needcopy = {"price": 100}
19 userinfo = {"user": "vincent"}
20 a = Example(needcopy, userinfo)
21 b = copy.deepcopy(a)
22 needcopy["title"] = "no"
23 userinfo["passwd"] = "none"
24 print "need: ", a.need, "; user: ", a.user
25 print "need: ", b.need, "; user: ", b.user
1 need:  {'price': 100, 'title': 'no'} ; user:  {'passwd': 'none', 'user': 'vincent'}
2 need:  {'price': 100} ; user:  {'passwd': 'none', 'user': 'vincent'}
Output

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM