第二章:数据结构-copy:复制对象-深副本中的递归

2.9.4 深副本中的递归
为了避免复制递归数据结构可能带来的问题,deepcopy()使用了一个字典来跟踪已复制的对象。将这个字典传入__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('\nCalling __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()方法将打印消息来显示这个方法如何调用的,并根据需要管理备忘字典内容。它不是复制整个连接列表,而是创建一个新列表,再把各个连接的副本追加到这个列表。这样可以确保复制各个新节点时会更新备忘字典,而避免递归问题或多余的节点副本。与前面一样,完成时会返回复制的对象。
在这里插入图片描述
图2-1 带环对象图的深副本
图2-1中的图有几个环,不过利用备忘字典处理递归就可以避免遍历导致栈溢出错误。复制根节点root时,会生成以下输出:在这里插入图片描述
第二次遇到root节点时,正在复制a节点,deepcopy()检测到递归,会重用备忘字典中现有的值,而不是创建一个新对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值