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

 

 

posted @ 2013-09-15 16:53  vin_yan  阅读(6134)  评论(0编辑  收藏  举报