浅拷贝copy.copy()仅复制外层对象,嵌套可变对象仍共享引用;深拷贝copy.deepcopy()递归复制所有层级,彻底隔离引用,但性能开销大且不支持不可序列化对象。

浅拷贝 copy.copy() 会共享嵌套对象的引用
当你用 copy.copy() 拷贝一个包含列表、字典或自定义对象的容器时,外层对象是新创建的,但内部可变对象仍指向原地址。这意味着修改嵌套元素会影响原对象。
常见错误现象:对拷贝后的 list 中的子列表 .append(),原列表也“被改了”。
- 适用场景:只有一层结构,或确认内部全是不可变对象(如
int、str、tuple) - 参数无差别:
copy.copy(x)和x.copy()(仅对部分内置类型有效)行为不同——后者是类型方法,不递归,且不支持嵌套字典等 - 性能较好,但无法隔离嵌套可变对象
深拷贝 copy.deepcopy() 递归复制所有层级
copy.deepcopy() 会为每个子对象都新建一份,彻底断开引用关系。适合处理含多层嵌套、含自定义类实例或需完全隔离的场景。
容易踩的坑:
- 遇到循环引用(比如对象 A 的属性指向 B,B 又指向 A)会报
RecursionError - 含文件句柄、线程锁、数据库连接等不可序列化对象时,直接抛
TypeError - 性能开销明显更大,尤其对大数据结构(如含百万级元素的嵌套
dict)
示例:deepcopy([{'a': [1, 2]}, {'b': {'c': 3}}]) 返回的新列表及其所有子结构都是独立副本。
自定义类要支持深拷贝,得实现 __deepcopy__
默认情况下,copy.deepcopy() 对自定义类实例会尝试逐个拷贝其 __dict__ 属性。但如果类里有不能直接拷贝的字段(如 threading.Lock()),就会失败。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
解决方式是显式定义 __deepcopy__ 方法:
def __deepcopy__(self, memo):
new_obj = self.__class__.__new__(self.__class__)
memo[id(self)] = new_obj
for k, v in self.__dict__.items():
setattr(new_obj, k, copy.deepcopy(v, memo))
return new_obj
注意:memo 参数必须传入递归调用,否则循环引用检测失效;若某字段不该被深拷贝(如缓存或单例引用),就在里面手动处理。
别用 json.loads(json.dumps(x)) 替代 deepcopy
这个技巧常被误当作“通用深拷贝”,但它只适用于 JSON 可序列化的类型(dict、list、str、int、float、bool、None)。一旦遇到 set、tuple(会被转成 list)、datetime、自定义类或函数,立刻报错或静默损坏数据。
更隐蔽的问题:
- 键名如果是非字符串类型(如
{(1,2): 'val'}),dumps会直接失败 - 浮点精度可能因字符串转换丢失(如
1.1存为"1.1000000000000001") - 所有
tuple都变成list,int键转成str键
真要序列化中转,优先选 pickle,但要注意安全性 —— 别反序列化不可信来源的数据。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










