浅拷贝只复制外层容器,嵌套可变对象仍共享内存地址;深拷贝递归复制所有层级,但受限于循环引用、不可序列化对象及自定义类缺陷。

因为浅拷贝只复制外层容器,嵌套的 list、dict 等可变对象仍共享内存地址;深拷贝则递归复制每一层,确保所有嵌套对象都是新实例——这是行为差异的根本原因。
浅拷贝修改嵌套列表时原对象跟着变
你看到的“改了副本,原对象也变了”,不是 bug,是浅拷贝的设计逻辑:它只新建最外层容器(比如新 list 对象),但里面每个元素仍是原对象的引用。如果某个元素本身是 [3, 4] 这样的列表,那副本和原对象指向的是同一个 list 实例。
-
copy.copy()、list.copy()、[:]、list(original)全是浅拷贝,行为一致 - 修改顶层元素(如
shallow[0] = 99)不影响原对象,因为这是在替换引用 - 修改嵌套可变对象内部(如
shallow[1].append(5))会同步到原对象,因为shallow[1]和original[1]是同一个对象 - 验证方法:打印
id(original[1])和id(shallow[1]),值相同 → 共享引用
deepcopy 能隔离嵌套列表,但有三个硬限制
copy.deepcopy() 确实能让你安全地修改 deep[1].append(5) 而不波及原对象,但它不是万能解药,三类情况会直接失败或出错:
- 遇到循环引用(A 引用 B,B 又引用 A)→ 抛
RecursionError或卡死 - 对象含不可序列化内容(如
open('x.txt')、threading.Lock())→ 抛TypeError - 自定义类重写了
__reduce__或__getstate__,但逻辑有缺陷 → 拷贝后状态异常,比如缓存字段丢失或重复初始化
别盲目用 deepcopy,先看数据结构和性能需求
对纯 JSON 兼容数据(dict/list/str/int 等),json.loads(json.dumps(obj)) 往往比 copy.deepcopy() 快 3–5 倍,且天然规避循环引用问题;但要注意它不支持 datetime、set、bytes 等类型。
立即学习“Python免费学习笔记(深入)”;
- 处理
pandas.DataFrame或numpy.ndarray?直接用.copy(deep=True),它们内部做了专用优化,不用copy.deepcopy() - 只有一两层嵌套,且你知道哪些子对象需要隔离?用
copy.copy()+ 手动重建关键嵌套层(如new[2] = original[2][:]),更轻量 - 不确定是否真需要完全隔离?先检查是否只是读操作,或能否用不可变结构(如
tuple包裹嵌套list)避免误改
最容易被忽略的点是:验证深拷贝是否生效时,只比对顶层 id() 不够,必须逐层检查嵌套对象的 id() —— 尤其是第二层,跳过这步,90% 的人会误以为“已经拷贝成功”。


















