• Python3标准库:copy复制对象


    1. copy复制对象

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

    1.1 浅副本

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

    import copy
    import functools
    
    @functools.total_ordering
    class MyClass:
    
        def __init__(self, name):
            self.name = name
    
        def __eq__(self, other):
            return self.name == other.name
    
        def __gt__(self, other):
            return self.name > other.name
    
    a = MyClass('a')
    my_list = [a]
    dup = copy.copy(my_list)
    
    print('             my_list:', my_list)
    print('                 dup:', dup)
    print('      dup is my_list:', (dup is my_list))
    print('      dup == my_list:', (dup == my_list))
    print('dup[0] is my_list[0]:', (dup[0] is my_list[0]))
    print('dup[0] == my_list[0]:', (dup[0] == my_list[0]))

    作为一个浅副本,并不会复制MyClass实例,所以dup列表中的引用会指向my_list中相同的对象。

    1.2 深副本

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

    将前例中的copy()调用替换为deepcopy(),可以清楚地看出输出的不同。

    import copy
    import functools
    
    @functools.total_ordering
    class MyClass:
    
        def __init__(self, name):
            self.name = name
    
        def __eq__(self, other):
            return self.name == other.name
    
        def __gt__(self, other):
            return self.name > other.name
    
    a = MyClass('a')
    my_list = [a]
    dup = copy.deepcopy(my_list)
    
    print('             my_list:', my_list)
    print('                 dup:', dup)
    print('      dup is my_list:', (dup is my_list))
    print('      dup == my_list:', (dup == my_list))
    print('dup[0] is my_list[0]:', (dup[0] is my_list[0]))
    print('dup[0] == my_list[0]:', (dup[0] == my_list[0]))

    列表的第一个元素不再是相同的对象引用,不过比较这两个对象时,仍认为它们是相等的。

    1.3 定制复制行为

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

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

    调用__deepcopy__(),并提供一个备忘字典,这会返回对象的一个深副本。所有需要深复制的成员属性都要连同备忘字典传递到copy.deepcopy()以控制递归(备忘字典将在后面更详细地解释)。

    import copy
    import functools
    
    @functools.total_ordering
    class MyClass:
    
        def __init__(self, name):
            self.name = name
    
        def __eq__(self, other):
            return self.name == other.name
    
        def __gt__(self, other):
            return self.name > other.name
    
        def __copy__(self):
            print('__copy__()')
            return MyClass(self.name)
    
        def __deepcopy__(self, memo):
            print('__deepcopy__({})'.format(memo))
            return MyClass(copy.deepcopy(self.name, memo))
    
    a = MyClass('a')
    
    sc = copy.copy(a)
    dc = copy.deepcopy(a)

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

    1.4 深副本中的递归

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

    import copy
    
    class Graph:
    
        def __init__(self, name, connections):
            self.name = name
            self.connections = connections
    
        def add_connection(self, other):
            self.connections.append(other)
    
        def __repr__(self):
            return 'Graph(name={}, id={})'.format(
                self.name, id(self))
    
        def __deepcopy__(self, memo):
            print('
    Calling __deepcopy__ for {!r}'.format(self))
            if self in memo:
                existing = memo.get(self)
                print('  Already copied to {!r}'.format(existing))
                return existing
            print('  Memo dictionary:')
            if memo:
                for k, v in memo.items():
                    print('    {}: {}'.format(k, v))
            else:
                print('    (empty)')
            dup = Graph(copy.deepcopy(self.name, memo), [])
            print('  Copying to new object {}'.format(dup))
            memo[self] = dup
            for c in self.connections:
                dup.add_connection(copy.deepcopy(c, memo))
            return dup
    
    root = Graph('root', [])
    a = Graph('a', [root])
    b = Graph('b', [a, root])
    root.add_connection(a)
    root.add_connection(b)
    
    dup = copy.deepcopy(root)

    Graph类包含一些基本的有向图方法。可以利用一个名和一个列表(包含已连接的现有节点)初始化一个graph实例。add_connection()方法用于建立双向连接。深复制操作符也用到了这个方法。

    __deepcopy__()方法将打印消息来显示这个方法是如何调用的,并根据需要管理备忘字典内容。它不是复制整个连接列表,而是创建一个新列表,再把各个连接的副本追加到这个列表。这样可以确保复制各个新节点时会更新备忘字典,而避免递归问题或多于的节点副本。与前面一页,完成时会返回复制的对象。

  • 相关阅读:
    Ubuntu 14.04的SWAP 为0
    堆和栈的区别(转过无数次的文章)
    加法乘法判断溢出(转)
    大端格式、小端格式(转)
    Linux 目录操作和4中文件拷贝效率测试
    Linux使用标准IO的调用函数,分3种形式实现
    支持 onload 事件的元素
    $().each() 和 $.each()
    npm install --save 与 npm install --save-dev 的区别
    <!DOCTYPE html>作用
  • 原文地址:https://www.cnblogs.com/liuhui0308/p/12346847.html
Copyright © 2020-2023  润新知