最稳妥的深拷贝方式是直接使用copy.deepcopy,仅在遇到不可序列化对象或需控制初始化逻辑时才手动干预;可通过定义__deepcopy__方法精准控制字段拷贝行为,或基于__dict__手动重建实例,而json序列化并非真正的深拷贝。

直接用 copy.deepcopy 是最常用也最稳妥的方式,但遇到自定义类、不可序列化对象或需要控制初始化逻辑时,就得手动干预——关键不在“多写几行”,而在“绕过默认限制,保留语义一致性”。
优先走标准 deep copy 路径
绝大多数情况下,copy.deepcopy 已足够健壮。它会自动调用类的 __deepcopy__ 方法(如果定义了),否则递归拷贝 __dict__ 中的属性,并妥善处理循环引用、内置类型、函数、模块等边界情况。
- 只要类不涉及文件句柄、线程锁、数据库连接等不可复制资源,直接用就行
- 若报
TypeError: cannot pickle ...,说明对象含不可序列化成分,这时才需介入 - 无需重写
__deepcopy__也能工作,但定义它可精准控制哪些字段该拷、哪些该跳过或重建
自定义 __deepcopy__ 控制行为
在类内部明确定义 __deepcopy__,比外部写通用拷贝函数更清晰、更安全。它接收两个参数:memo(用于处理循环引用)和可选上下文,返回新实例。
- 对普通属性,调用
copy.deepcopy(value, memo) - 对需特殊处理的字段(如缓存、临时状态),跳过拷贝或设为默认值
- 对不可复制资源(如 socket、threading.Lock),新建一个干净实例或置为
None
例如:
class Config:def __init__(self, data, cache=None):
self.data = data
self.cache = cache # 不应深拷
def __deepcopy__(self, memo):
new_obj = Config(copy.deepcopy(self.data, memo))
new_obj.cache = None # 显式清空,不拷 return new_obj
兜底方案:基于 __dict__ 的可控重建
当无法修改原类(比如第三方库类),又必须规避 deepcopy 异常时,可手动重建实例。核心是两步:先用空参或默认参数构造新对象,再逐个拷贝关键属性。
- 用
obj.__class__()初始化,前提是类支持无参构造;否则需预设一组安全的**init_args - 遍历
obj.__dict__,对每个属性尝试copy.deepcopy;失败则降级为浅拷贝或跳过 - 最后清理目标对象中存在但源对象没有的冗余属性,避免残留状态
这种做法不追求“完全等价”,而是确保关键数据被复制、运行时不崩溃——适合配置类、DTO 类等结构简单、逻辑轻量的对象。
慎用 JSON 序列化替代深拷贝
有人用 json.loads(json.dumps(obj)) 做“伪深拷贝”,但它有硬伤:
- 只支持基本类型(str/int/list/dict/bool/None),丢弃所有自定义类、函数、datetime、bytes 等
- 会抹掉方法、私有属性、元信息,结果是纯数据字典,不再是原类型实例
- 浮点精度、NaN、Inf 等特殊值可能出错
除非你明确只要扁平化的数据快照,否则这不是深拷贝,只是数据导出。











