浅拷贝只复制第一层,嵌套对象仍共享引用;深拷贝递归复制所有层级,彻底隔离修改;不可变类型拷贝无意义;自定义类需实现__deepcopy__支持安全深拷贝。

浅拷贝只复制第一层,嵌套对象还是共用引用
当你用 copy.copy() 或切片(如 list[:] )、dict.copy() 复制一个含嵌套结构的对象时,新对象的顶层是独立的,但内部的列表、字典、自定义对象等依然指向原对象的同一内存地址。这意味着改子对象,两边都会变。
常见错误现象:original = [[1, 2], [3]]; shallow = copy.copy(original); shallow[0].append(99); print(original) # 输出 [[1, 2, 99], [3]]
- 适用场景:确定数据是纯一层结构(比如全是数字、字符串),或故意要共享子对象状态
- 注意
list.copy()和dict.copy()本质也是浅拷贝,别被方法名误导 - 性能上比深拷贝快得多,因为不递归遍历
深拷贝递归复制所有层级,彻底隔离修改影响
copy.deepcopy() 会逐层遍历对象树,为每个可变子对象新建实例,并维护引用关系映射,避免无限递归(比如循环引用)。它真正实现“完全独立”。
使用场景:配置字典带嵌套、测试中需复位原始 fixture、解析 JSON 后二次加工又不想污染源数据
立即学习“Python免费学习笔记(深入)”;
- 参数只有
obj和可选的memo(用于手动控制缓存,极少见) - 兼容性没问题,但对含不可序列化对象(如文件句柄、线程锁、lambda)会抛
TypeError: cannot pickle ... - 性能开销明显——深度越深、对象越多,耗时和内存增长越显著
哪些类型默认就是“不可变”,拷贝无意义
对 int、str、tuple(且其元素也全不可变)、frozenset 等类型,浅拷贝和深拷贝行为一致:都返回原对象本身(id 不变),因为它们无法被原地修改。
例如:a = (1, 2); b = copy.copy(a); c = copy.deepcopy(a); print(id(a) == id(b) == id(c)) # True
- 这不是 bug,是 Python 的优化机制;但容易让人误以为“拷贝失败”
- 判断是否真需要拷贝,先看变量类型和实际是否会被重新赋值(
a = ...)或原地修改(.append()) - 如果只是传参防误改,用不可变类型天然安全,不用额外拷贝
自定义类要支持深拷贝,得自己实现 __deepcopy__
默认情况下,copy.deepcopy() 对自定义类实例会尝试调用其 __init__() 并填入原对象属性值,但这常出错——比如构造函数有强制参数、或属性本身不能直接复制(如 socket 连接)。
正确做法是在类里定义 __deepcopy__(self, memo) 方法,显式控制每个字段怎么复制:
def __deepcopy__(self, memo):
new_obj = MyClass.__new__(MyClass)
memo[id(self)] = new_obj
new_obj.data = copy.deepcopy(self.data, memo) # 关键:手动深拷贝关键字段
new_obj._cache = None # 非必要字段可重置
return new_obj
- 漏写
memo参数会导致递归崩溃(报RecursionError) - 忘记调用
copy.deepcopy(..., memo)而直接用copy.copy(),嵌套部分就退化为浅拷贝 - 若类不含可变状态(比如纯数据容器),其实可以跳过这步,靠默认逻辑也能工作
深拷贝不是银弹,尤其在处理大嵌套结构、含外部资源对象或循环引用时,很容易卡住或报错;而浅拷贝看似简单,一不留神就在多处悄悄共享了状态。到底用哪个,得看你真正想隔离的是哪一层。










