浅拷贝只复制顶层,嵌套对象仍共享引用;深拷贝递归复制全部层级,彻底隔离但性能开销大;选型取决于数据结构、修改需求及对象可序列化性。

浅拷贝只复制顶层,嵌套对象仍共享引用
当你用 copy.copy() 或切片(如 list[:] )做浅拷贝时,新对象本身是独立的,但其中包含的可变对象(比如列表里的子列表、字典的值是另一个字典)仍然指向原对象的同一内存地址。这意味着修改嵌套内容会同时影响原对象和拷贝对象。
常见错误现象:new_list = copy.copy(old_list) 后,new_list[0].append(99) 导致 old_list[0] 也多了 99。
- 适用场景:确定数据结构只有单层、或所有嵌套项都是不可变对象(如字符串、数字、元组)
- 性能优势:开销小,不递归遍历,适合大数据量但结构扁平的情况
- 注意陷阱:对
dict浅拷贝后,new_dict['key'] is old_dict['key']可能为True(如果值是列表或自定义类实例)
深拷贝递归复制全部层级,彻底隔离
copy.deepcopy() 会逐层遍历对象及其所有嵌套内容,为每个可变子对象都新建一份内存空间。因此修改任意层级都不会波及原始对象。
但不是万能解法:遇到循环引用(比如对象 A 的属性指向 B,B 又指向 A)时,deepcopy 能检测并避免无限递归;但遇到不可序列化的对象(如文件句柄、线程锁、某些 C 扩展对象),会直接抛出 TypeError: unshallowable object。
立即学习“Python免费学习笔记(深入)”;
- 必须显式导入:
import copy,不能直接用deepcopy() - 性能代价明显:时间与内存开销随嵌套深度和对象数量增长,大数据结构慎用
- 自定义类若需控制深拷贝行为,应实现
__deepcopy__(self, memo)方法
不可变对象在浅拷贝中“看起来像深拷贝”
字符串、数字、元组(且其元素也全不可变)这类对象,即使被浅拷贝,也不会出现共享修改的问题——因为它们无法被原地修改。例如 a = (1, 2); b = copy.copy(a),a is b 往往为 True,但这只是 Python 的小整数/短字符串缓存或元组驻留优化,并非拷贝逻辑所致。
- 不要依赖这种行为判断是否安全:一旦元组里有列表(如
(1, [2, 3])),浅拷贝后修改子列表仍会互相影响 - 检查是否真隔离,用
id()或is比较嵌套项,而不是只看顶层 - 不可变性是类型特性,不是拷贝方式的结果;混淆这点容易在重构时引入 bug
实际选型关键看数据结构和修改意图
没有“默认该用哪个”的答案。重点是你后续会不会修改嵌套内容,以及能否接受性能损耗。
- 只读场景或纯扁平结构 →
copy.copy()或构造新容器(如list(old)、dict(old))足够 - 要写入嵌套字段且需完全隔离 → 必须
copy.deepcopy(),但先确认对象不含不可拷贝成分 - 想省性能又需部分隔离?手动构造 + 选择性深拷贝关键字段,比如
{'config': copy.deepcopy(d['config']), 'name': d['name']}
最常被忽略的一点:第三方库返回的对象(如 pandas DataFrame、requests.Response.json() 结果)可能表面像 dict/list,实则封装了特殊逻辑,盲目 deepcopy 不仅慢,还可能失败或破坏内部状态。










