讲师中心 微信公众号
AI工具推荐 视频效率加速

Python中如何深拷贝包含循环引用的复杂嵌套结构?

云磊大大_7031

云磊大大_7031

发布时间:2026-10-08 08:22:17

|

923人浏览过

|

来源于php中文网

原创

deepcopy在循环引用时因memo机制失效或递归过深触发RecursionError;应重写__deepcopy__、用weakref解耦、避免拷贝不可序列化对象。

python中如何深拷贝包含循环引用的复杂嵌套结构?

deepcopy 为什么在循环引用时卡住或报 RecursionError

Python 的 copy.deepcopy() 内部靠 memo 字典缓存已拷贝对象的 id() 来识别并跳过重复递归,但这个机制依赖“对象可哈希且 ID 稳定”。一旦类重写了 __eq__ 或 __hash__,导致 id() 比较失效(比如用弱引用、代理对象或自定义内存管理),memo 就可能漏判循环;更常见的是嵌套层级过深(>1000 层),触发默认的 sys.getrecursionlimit() 限制。

典型错误现象:RecursionError: maximum recursion depth exceeded,或进程长时间无响应(尤其在含大量图结构、双向链表、事件监听器绑定的类实例中)。

  • 不要临时调用 sys.setrecursionlimit(3000) —— 这只是掩盖问题,上线环境极易因栈溢出崩溃
  • 检查是否无意中让方法闭包捕获了 self(如 lambda 中引用实例属性),这类引用不会出现在 obj.__dict__ 里,但会被 deepcopy 追踪到
  • 确认对象里没混入不可拷贝类型:文件句柄、线程锁、C 扩展对象(如某些数据库连接)会直接抛 TypeError: unshallowable object

手动控制 deepcopy 流程:重写 __deepcopy__ 方法

对自定义类,最稳妥的方式是显式接管深拷贝逻辑,避免盲目递归。重点不是“全拷”,而是“只拷该拷的”。

示例场景:一个带双向父子引用的树节点类:

立即学习“Python免费学习笔记(深入)”;

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []
        self.parent = None  # 循环引用来源
<pre class="brush:php;toolbar:false;">def __deepcopy__(self, memo):
    # 创建新实例,跳过 parent(避免循环)
    new_obj = TreeNode(self.value)
    memo[id(self)] = new_obj
    # 只深拷 children,parent 留空,后续由上层逻辑重建关系
    new_obj.children = copy.deepcopy(self.children, memo)
    return new_obj

python-pro
python-pro

高级 Python 特性、异步编程、性能调优、静态类型、内存管理、Python 内部机制及生态库方面的专家。

下载
  • memo 必须传给子对象的 copy.deepcopy() 调用,否则子级递归会重新建 memo,破坏循环检测
  • 不要在 __deepcopy__ 里调用 copy.deepcopy(self) —— 会无限递归
  • 若需保留 parent 关系,应在拷贝完成后由外部统一重建(如遍历新树补 parent 指针),而非在拷贝过程中强求

绕过 deepcopy:用 weakref 或 ID 映射解耦循环

很多所谓“循环引用”本质是设计冗余。与其硬扛深拷贝,不如提前消除强循环。

常见重构方式:

  • 把 self.parent 改成 self._parent_id: int,配合全局 registry 查找,彻底断开引用链
  • 用 weakref.ref 替代强引用:self._parent_ref = weakref.ref(parent),这样 deepcopy 不会追踪它(weakref 对象本身不可拷贝,但不会引发循环)
  • 对图结构,改用邻接表 + 索引 ID,而非对象直连:self.neighbors = [node.id for node in raw_neighbors],拷贝时只复制 ID 列表,重建时再查表

注意:weakref.ref 在被拷贝对象销毁后会自动变为 None,所以使用前必须加 if ref() is not None 判断。

NumPy 数组、datetime、枚举等特殊对象别乱用 deepcopy

copy.deepcopy() 对标准库外的类型支持有限,强行使用反而出错。

  • numpy.ndarray:必须用 a.copy(),deepcopy(a) 可能破坏 dtype 或 strides,旧版 NumPy 甚至抛 AttributeError: 'numpy.ndarray' object has no attribute '__dict__'
  • datetime、enum.Enum、frozenset 等不可变对象,deepcopy 实际返回原对象(因为无需拷),但代码逻辑若假设“深拷贝一定新建对象”,就会埋下隐性 bug
  • 含 __slots__ 的类,deepcopy 默认不拷 __slots__ 外字段;若用了描述符或 property,需在 __deepcopy__ 里显式处理

真正难的不是写对一行 copy.deepcopy(x),而是判断 x 里哪些部分本就不该被拷——比如配置里的 logger 实例、全局计数器、缓存池句柄。这些往往比循环引用更容易被忽略。

热门AI工具

更多
切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

1671

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

4204

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1669

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

24437

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2987

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

3007

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

1163

2023.08.11

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

596

2023.08.10

FrankenPHP集成Laravel详细教程
FrankenPHP集成Laravel详细教程

本专题提供FrankenPHP集成Laravel的详细配置指南,全面解析运行原理、开发环境搭建、Caddyfile配置、Octane工作模式、数据库连接、队列任务、定时任务和生产环境优化,解决部署过程中常见的报错与兼容性问题。

0

2026.10.08

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn