Copy – 复制对象

作用:提供一些函数,可以使用浅副本或深副本语义复制对象。

copy模块包括两个函数copy()和deepcopy(),用于复制现有的对象

1、  浅副本

copy()创建的浅副本(shallow copy)是一个新容器,其中填充原对象内容的引用。建立list对象的一个浅副本时,会构造一个新的list,并将原对象的元素追加到这个list。

 import copy

 class MyClass(object):
def __init__(self,name):
self.name = name
def __cmp__(self,other):
return cmp(self.name,other.name) a = MyClass('a')
my_lt = [a]
dup = copy.copy(my_lt)
print ' my_lt:',my_lt
print ' dup:',dup
print ' dup is my_lt:',(dup is my_lt)
print ' dup == my_lt:',(dup == my_lt)
print 'dup[0] is my_lt[0]:',(dup[0] is my_lt[0])
print 'dup[0] == my_lt[0]:',(dup[0] == my_lt[0])

运行结果:

__cmp__() 在比较类实例时被调用

对于一个浅副本,不会复制Myclass实例,所以dup列表中的引用会指向my_lt中相同的对象

2、  深副本

deepcopy()创建的深副本是一个新的容器,其中填充源对象内容的副本.要建立一个list的深副本,会构成一个新的list,复制原列表的元素,然后将这些副本追加到新列表。

 import copy

 class MyClass(object):
def __init__(self,name):
self.name = name
def __cmp__(self,other):
return cmp(self.name,other.name) a = MyClass('a')
my_lt = [a]
dup = copy.deepcopy(my_lt)
print ' my_lt:',my_lt
print ' dup:',dup
print ' dup is my_lt:',(dup is my_lt)
print ' dup == my_lt:',(dup == my_lt)
print 'dup[0] is my_lt[0]:',(dup[0] is my_lt[0])
print 'dup[0] == my_lt[0]:',(dup[0] == my_lt[0])

运行结果:
  

3、  定制复制行为

可以使用特殊方法__copy__() 和__deepcopy__()来控制如何建立副本。

·调用__copy__()而不提供任何参数,这会返回对象的一个浅副本。

·调用__deepcopy__(),并提供一个北方字典,这回返回对象的一个深副本。所有需要深复制的成员属性都要连同备忘字典传递到copy.deepcopy()来控制递归。

例如:

 import copy

 class MyClass(object):
def __init__(self,name):
self.name = name
def __cmp__(self,other):
return cmp(self.name,other.name)
def __copy__(self):
print '__copy__()'
return MyClass(self.name)
def __deepcopy__(self,memo):
print '__deepcopy__(%s)' % str(memo)
return MyClass(copy.deepcopy(self.name, memo,)) a = MyClass('a')
sc = copy.copy(a)
dc = copy.deepcopy(a)

运行结果:

  

备忘字典用于跟踪已复制的值,以避免无限递归

4、  深副本中的递归

为了避免复制递归数据结构可能带来的问题,deepcopy()使用一个字典来跟踪已复制的对象。将这个歌字典传入__deepcopy__() 方法,从而在该方法中也可以进行检查。

下面的例子显示了一个互连的数据结构(如图1)可以通过实现__deepcopy__()方法帮助防止递归。

图1

 class Graph(object):

     def __init__(self,name,connections):
self.name = name
self.connections = connections
def add_connections(self,other):
self.connections.append(other) def __repr__(self):
return 'Graph(name=%s,id=%s)' % (self.name,id(self))
def __deepcopy__(self,memo):
print '\nCalling __deepcopy__ for %r' % self
if self in memo:
existing = memo.get(self)
print ' Already copied to %r' % existing
return existing
print ' Memo dictionary'
pprint.pprint(memo,indent=4,width=40)
dup = Graph(copy.deepcopy(self.name, memo),[])
print ' Copying to new object %s' % dup
memo[self] = dup
for c in self.connections:
dup.add_connections(copy.deepcopy(c, memo))
return dup root = Graph('root',[])
a = Graph('a',[root])
b = Graph('b',[a,root])
root.add_connections(a)
root.add_connections(b) dup = copy.deepcopy(root)

  Graph类包含一些基本的有向图方法。基于一个名和已连接的现有节点的一个列表可以初始化一个Graph实例。add_connection()方法用于建立双向谅解deepcopy也用到了这个方法__deepcopy__()方法将打印消息来显示它如何得到调用,

并根据需要管理备忘录字典内容。它不是复制整个链接列表,而是创建一个新的列表,把各个连接的副本追加到这个列表。这样可以确保复制各个新节点时会更新备忘录字典,以免递归问题或多余的节点副本。与前面一样,完成时会返回复制的对象。

如图1 中存在几个环,不过利用备忘录字典处理递归就可以避免遍历导致栈溢出错误。复制根节点root时,输入如下:

    

第二次遇到root节点时,此时正在复制a节点,__deepcopy__()检测到递归,会重用备忘录字典中现有的值,而不是创建一个新对象。

每日一“酷”之copy的更多相关文章

  1. 每日一“酷”之Cookie

    Cookie---Http Cookie 作用:Cookie模块定义一些类来解析和创建HTTP cookie首部 Cookie模块为大多数符合RFC 2109的cookie实现一个解析器.这个实现没有 ...

  2. 每日一“酷”之Queue

    Queue—线程安全的FIFO实现 作用:提供一个线程安全的FIFO实现 Queue模块提供了一个适用于多线程编程的先进先出(first-in,first-out)数据结构,可以用来在生产者和消费者线 ...

  3. 每日一“酷”之pprint

    pprint – 美观打印 作用:美观打印数据结构 pprint 包含一个“美观打印机”,用于生成数据结构的一个美观视图.格式化工具会生成数据结构的一些表示,不仅可以由解释器正确地解析,而且便于人类阅 ...

  4. 每日一“酷”之heapq

    作用:heapq模块实现一个适用于Python列表的最小堆排序算法 堆(heap)是一个属性数据结构,其中子节点与父节点是一种有序关系.二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全 ...

  5. 每日一“酷”之bisect

    作用:维护有序列表,而不必在每次想列表增加一个元素时调用sort排序 bisect 模块实现了一个算法用于向列表中插入元素,同时仍保持列表有序.有些情况下,这比反复对一个了表序列更高效,另外也比构建一 ...

  6. 每日一“酷”之array

    array--国定类型数据序列 array模块定义一个序列数据结构,看起来和list非常相似,只不过所有成员都必须是相同的基本类型. 1.初始化 array实例化时可以提高一个参数来描述允许哪个种数据 ...

  7. 每日一“酷”之difflib

    介绍:difflib 比较序列.该模块包含一些用来计算和处理序列直接差异的工具.她对于比较文本尤其用,其中包含的函数可以使用多种常用差异格式生成报告. 测试数据(splitlines()按行划分为序列 ...

  8. 每日一“酷”之textwrap

    介绍:需要美观打印时,可以使用textwrap模块来格式化要输出的文本,这个模块允许通过编程提高类似段落自动换行或填充特性等功能. 1 创建实例数据 sample_text = ''' I’m ver ...

  9. 每日一“酷”之string

    介绍:string模块可以追溯到最早的Python版本中.现在很多的被移植为str和unicode对象的方法,在python3.0中会被完全去除.string模块中,有很多有用的常量和累,用来处理st ...

随机推荐

  1. 【Linux/Ubuntu学习 14】Linux下查看文件和文件夹大小

    当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择. df可以查看一级文件夹大小.使用比例.档案系统及其挂入点,但对文件却无能为力.    du可以查看文件及文件夹的大小. ...

  2. 【Linux/Ubuntu学习 7】E: 无法获得锁 /var/lib/dpkg/lock – open (11: 资源暂时不可用) E: 无法锁定管理目录

    在用sudo apt-get install 安装软件时,由于速度太慢,想换个软件源,直接关闭了终端,apt-get但进程没有结束,结果终端提示 :“E: 无法获得锁 /var/lib/dpkg/lo ...

  3. git 删除已经 add 的文件

    使用 git rm 命令即可,有两种选择, 一种是 git rm --cached "文件路径",不删除物理文件,仅将该文件从缓存中删除: 一种是 git rm --f " ...

  4. 分享一个关于jackson的Json工具类

    直接贴代码: import org.codehaus.jackson.map.DeserializationConfig.Feature; import org.codehaus.jackson.ma ...

  5. nodejs5-package.json

    name:包名,唯一,由小写字符.数字和下划线组成,不能有空格 preferglobal:是否支持全局安装,true表示支持 descrition:描述 version:版本号 author:作者信息 ...

  6. Javascript获取URL地址变量参数值的方法

    今天碰到在做一个动态页面的时候,需要用到 URL 的参数值来作判断,从而决定某一块内容在当前页面是否显示.例如exampe.html?parm1=xxx&parm2=xxx&parm3 ...

  7. 全选按钮的设定和POST处理当前循环的列表

    以下为全选按钮的代码,通过class实现. //全选按钮 $(function () { $("#selectall").change(function () { var isch ...

  8. 网站添加到IIS和附件进程调试(新手使用篇)

    一.网站添加到IIS 做网站开发,很有必要把项目添加到IIS中,这对浏览和后期的调试很有帮助.怎么把网站添加到IIS上? 1). 打开IIS,然后操作步骤如下图: 选择Default Web Site ...

  9. jQuery骨架

    jQuery选择器 jQuery操作DOM jQuery中的事件与应用 jQuery的动画与特效 Ajax在jQuery中的应用 jQuery常用插件 jQuery UI插件 jQuery实用工具函数 ...

  10. ARM你必须知道的事儿——为啥“PC = PC + 8”?

    为啥是“PC = PC + 8”: “PC = PC + 8”其实这样写容易让人蒙了.“PC = PC + 8”真正含义应该是: 执行处代码地址 = PC - 8: 也就是说,”PC指向的地址“领先“ ...