资讯动态

为什么拷贝会踩坑?memory_graph图解赋值、浅拷贝与深拷贝的3种行为

发布时间:2026/10/15 17:29:42 来源:尧图企业网站定制
【免费下载链接】memory_graphTeaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.项目地址https://gitcode.com/gh_mirrors/me/memory_graph点击查看免费下载在 Python 中给一个变量赋值时数据到底是被复制了还是只共享了一份引用b a、copy.copy(a)、copy.deepcopy(a)三种拷贝行为各有差异稍有不慎就会改出隐藏 Bug。开源工具memory_graph能把变量与数据之间的引用关系画成内存图帮你一眼看清 Python 赋值、浅拷贝与深拷贝的 3 种行为是学习 Python 数据模型引用、可变性的绝佳图解工具。 快速上手两行代码画出内存图先安装 memory_graph需要 Graphvizpip install --upgrade memory_graph核心 API 只有三个函数mg.show(data)把数据的结构可视化出来mg.render(data, out.png)渲染成图片文件也支持 pdf / svg / gvmg.block(...)执行函数后阻塞等待回车方便逐步观察import memory_graph as mg a [1, 2] b a # b 和 a 是同一份 list mg.show(locals()) # 画出所有局部变量的引用关系locals()会返回当前作用域所有局部变量的字典是最常用的观察入口。下面用同一个嵌套列表逐一图解 3 种行为。 行为一赋值Assignment——什么都没拷贝a [4, 3, 2] b a b.append(1) # 改 b 会同时改 a这里b a只是让b这个名字也指向a所引用的那个 list两个变量共享同一份数据。print看不出来问题但内存图一目了然a和b两根箭头指向同一个 list 节点。mg.render(locals(), mutable2.png)生成的图正是 mutable.py 的运行结果——图中dict里并列着a、b箭头汇合到同一个 list 上 验证小技巧id(a) id(b)或a is b为True时说明两者共享同一对象。 行为二浅拷贝 copy.copy——只复制最外层对一个嵌套列表做浅拷贝时只有第一层是新列表里面嵌套的子列表依然是共享的import copy a [ [1, 2], [x, y] ] c1 a # 行为一赋值全部共享 c2 copy.copy(a) # 行为二浅拷贝只复制第一层 c3 copy.deepcopy(a) # 行为三深拷贝完全不共享 mg.show(locals())生成的图中有三个 list 顶层节点c1与a共用一个c2有自己的顶层 list但它的两个子列表与a的子列表是同一批节点只有c3的整棵子树都独立了。这个例子来自 src/copies.py可直接运行复现。行为三深拷贝 copy.deepcopy——整棵树都独立copy.deepcopy(a)会递归复制所有层级改c3的任何一处都不会波及a。在 Marimo 这类交互式环境中还能结合调用栈一起看四种拷贝赋值、.copy()、自定义拷贝、deepcopy的对比三种行为速查表写法行为顶层嵌套子对象c1 a赋值共享共享c2 copy.copy(a)等价a.copy()、a[:]、list(a)浅拷贝新列表共享c3 copy.deepcopy(a)深拷贝新列表全部新对象 进阶自定义拷贝Custom Copy有时标准三种行为都不满足需求——比如对象里digits想复制、letters想共享。这时可以自己写拷贝方法src/custom_copy.py 给出了范例def custom_copy(self): Copies digits but shares letters. c copy.copy(self) c.digits copy.copy(self.digits) return c内存图中可以清楚看到a和b两个对象各自拥有独立的digits列表但letters指向同一个 list 节点 易错点不可变类型下拷贝与赋值等价tuple、int、str等不可变类型无法原地修改修改时 Python 会自动产生新值所以提前拷贝毫无意义。memory_graph 对此做了优化copy.copy(a)和copy.deepcopy(a)对不可变类型都会退化为赋值省时间也省内存混合了可变与不可变值的结构也一样——深拷贝会尽量少复制不可变部分只保证每个可变值都有副本 实战调试在 IDE 里持续观察拷贝过程拷贝相关的 Bug 往往在运行中才暴露。推荐做法在调试器的watch里加入mg.render(locals(), my_graph.pdf)然后单步调试时 PDF 会实时更新所有局部变量的引用关系——下图就是在 Visual Studio Code 中调试拷贝行为时的效果另外两个高频陷阱建议结合内存图对照记忆b [300]原地改会影响共享者a但b [400, 500]重新绑定名字不会影响a函数传参时参数与实参共享可变对象给函数传c.copy()副本才能隔离修改更多示例可在仓库的 src/ 目录中找到例如 src/rebind.py重绑定、src/function_call.py函数调用共享。 总结建立正确的 Python 心智模型问题答案b a拷贝了吗没有只是共享引用改b会影响a吗可变类型且共享时——会要完全独立怎么办copy.deepcopy(a)如何直观确认谁和谁共享mg.show(locals())画图memory_graph 通过memory_to_nodesmemory_graph/memory_to_nodes.py把内存中的对象按id()去重建图正是共享与拷贝最可靠的判据。遇到拿不准的数据流画一张图胜过十次print。赞分享【免费下载链接】memory_graphTeaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.项目地址https://gitcode.com/gh_mirrors/me/memory_graph点击查看免费下载相关推荐Java 深浅拷贝完全指南浅拷贝、深拷贝、延迟拷贝与序列化拷贝实战解析Java 深浅拷贝完全指南浅拷贝、深拷贝、延迟拷贝与序列化拷贝实战解析 本文以 YCBlogs 仓库中的《Java深浅拷贝》笔记为核心系统讲解 Java 对教程技术博客文档CANN asc-devkit SIMD-API C-API asc_int82int32函数asc_int82int32 废弃 产品支持情况 | 产品 | 是否支持 | | | : : | | Ascend 950PR/Ascend 950DT | √人工智能深度学习算子库CANNAscendNetdata Windows 监控静默安装 5 分钟从服务验证到告警闭环Netdata Windows 监控静默安装 5 分钟从服务验证到告警闭环 本文面向维护混合环境的系统管理员与 DevOps 工程师用 Netdata W可观测性指标监控告警异常检测创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑