zoukankan      html  css  js  c++  java
  • 每日一“酷”之copy

    Copy – 复制对象

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

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

    1、  浅副本

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

     1 import copy
     2 
     3 class MyClass(object):
     4     def __init__(self,name):
     5         self.name = name
     6     def __cmp__(self,other):
     7         return cmp(self.name,other.name)
     8  
     9 a = MyClass('a')
    10 my_lt = [a]
    11 dup = copy.copy(my_lt) 
    12 print '             my_lt:',my_lt
    13 print '               dup:',dup
    14 print '      dup is my_lt:',(dup is my_lt)
    15 print '      dup == my_lt:',(dup == my_lt)
    16 print 'dup[0] is my_lt[0]:',(dup[0] is my_lt[0])
    17 print 'dup[0] == my_lt[0]:',(dup[0] == my_lt[0])

    运行结果:

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

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

    2、  深副本

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

     1 import copy
     2 
     3 class MyClass(object):
     4     def __init__(self,name):
     5         self.name = name
     6     def __cmp__(self,other):
     7         return cmp(self.name,other.name)
     8  
     9 a = MyClass('a')
    10 my_lt = [a]
    11 dup = copy.deepcopy(my_lt) 
    12 print '             my_lt:',my_lt
    13 print '               dup:',dup
    14 print '      dup is my_lt:',(dup is my_lt)
    15 print '      dup == my_lt:',(dup == my_lt)
    16 print 'dup[0] is my_lt[0]:',(dup[0] is my_lt[0])
    17 print 'dup[0] == my_lt[0]:',(dup[0] == my_lt[0])

    运行结果:
      

    3、  定制复制行为

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

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

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

    例如:

     1 import copy
     2 
     3 class MyClass(object):
     4     def __init__(self,name):
     5         self.name = name
     6     def __cmp__(self,other):
     7         return cmp(self.name,other.name)
     8     def __copy__(self):
     9         print '__copy__()'
    10         return MyClass(self.name)
    11     def __deepcopy__(self,memo):
    12         print '__deepcopy__(%s)' % str(memo)
    13         return MyClass(copy.deepcopy(self.name, memo,))
    14 
    15 a = MyClass('a')
    16 sc = copy.copy(a)
    17 dc = copy.deepcopy(a)

    运行结果:

      

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

    4、  深副本中的递归

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

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

                         图1

     1 class Graph(object):
     2     
     3     def __init__(self,name,connections):
     4         self.name = name
     5         self.connections = connections
     6     def add_connections(self,other):
     7         self.connections.append(other)
     8     
     9     def __repr__(self):
    10         return 'Graph(name=%s,id=%s)' % (self.name,id(self))
    11     def __deepcopy__(self,memo):
    12         print '
    Calling __deepcopy__ for %r' % self
    13         if self in memo:
    14             existing = memo.get(self)
    15             print '   Already copied to %r' % existing
    16             return existing
    17         print '   Memo dictionary'
    18         pprint.pprint(memo,indent=4,width=40)
    19         dup = Graph(copy.deepcopy(self.name, memo),[])
    20         print '   Copying to new object %s' % dup
    21         memo[self] = dup
    22         for c in self.connections:
    23             dup.add_connections(copy.deepcopy(c, memo))
    24         return dup
    25 
    26 root = Graph('root',[])
    27 a = Graph('a',[root])
    28 b = Graph('b',[a,root])
    29 root.add_connections(a)
    30 root.add_connections(b)
    31 
    32 dup = copy.deepcopy(root)

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

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

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

         

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

  • 相关阅读:
    css设置兄弟节点的样式(相邻的前一个节点)
    css文本强制两行超出就显示省略号,不显示省略号
    Adobe Photoshop CC2014 for MAC 详细破解步骤
    CSS实现背景图片透明和文字不透明效果
    jquery实现搜索框从中间向两边扩展(左右放大)
    微信小程序拒绝授权后提示信息以及重新授权
    linux下的 sudo ln -s 源文件 目标文件
    小程序实现倒计时:解决ios倒计时失效(setInterval失效)
    浅谈CSS高度坍塌
    sourcetree安装以及跳过sourcetree注册登录
  • 原文地址:https://www.cnblogs.com/victroy/p/4030043.html
Copyright © 2011-2022 走看看