python中copy和deepcopy区别
你说“Python 中 copy 和 deepcopy 的区别”这个话题,其实每次面试遇到这题我都忍不住想多讲两句。你说这玩意不是常识嘛,copy 一个对象,deepcopy 一个对象,不就是浅复制和深复制吗?但真到现场面试的时候,有多少人能答得又快又准?而且别忘了,Python 里万物皆对象,复制那可是个坑多得能开矿的老话题……
我们先讲人话:Python 里的 copy.copy() 叫做浅拷贝,copy.deepcopy() 是深拷贝。浅拷贝只是拷了一层皮,深拷贝是连骨头都扒了下来重新拼的。
举个简单但经典的例子👇:
import copy
a = [1, 2, [3, 4]]
b = copy.copy(a)
c = copy.deepcopy(a)
a[2][0] = 999
print("a:", a)
print("b:", b)
print("c:", c)
输出结果如下:
a: [1, 2, [999, 4]]
b: [1, 2, [999, 4]]
c: [1, 2, [3, 4]]
看到没?b 是浅拷贝,虽然它表面看起来是个新的 list,但里面嵌套的 [3, 4] 那一层,其实跟 a 共享同一块内存。所以当你改了 a[2][0],b 跟着就变了。但 c 是深拷贝,它自己把嵌套结构又复制了一份出来,互不干扰。
到这很多人会说,哦那我以后都用 deepcopy 吧,一劳永逸。你别说我真听过一个初级开发这么讲,结果后面踩了一堆坑。
为啥?因为 deepcopy 真不是万能药,它背后是递归的,如果你的数据结构特别深,或者出现了循环引用(比如节点指向自己或者互相指来指去),那 deepcopy 不是慢,就是炸…
比如你写了个链表结构(或者图结构),一不小心引用套引用,deepcopy 一下就要跟你死磕到底:
a = []
a.append(a)
copy.deepcopy(a) # RecursionError: maximum recursion depth exceeded
还有个冷门但实际项目里会遇到的事:某些对象你想拷,Python 偏偏不给拷。比如打开的文件句柄、网络连接、线程锁这些对象,用 deepcopy 根本没法拷,要么报错要么拷出来没用。Python 官方文档也说了,有些对象不支持 __deepcopy__ 协议,不好意思你得自己想办法。
所以我一直建议:用 copy 和 deepcopy 的时候,一定得先知道你拷的到底是什么结构。如果是简单的 list、dict、元组(里边是不可变对象)那还好说。如果是自定义的类、复杂的嵌套、第三方库生成的对象,那你最好自己实现 __copy__ 和 __deepcopy__ 方法,定制一下行为。要不然就是掉坑里挠头。
举个项目中的真实例子,我们以前有个用来缓存用户配置信息的类叫 UserConfig,里面嵌了一堆 dict + list,还有从 Redis 取的临时状态对象。我们图省事直接 deepcopy(config),结果缓存里的 Redis 连接对象也一起被拷了出来,后续连接池报错,一查才发现拷了一堆 socket 连接上来……直接背锅 🤦
后来我们改成了:
classUserConfig:
def__init__(self):
self.data = {...}
self._temp_state = RedisConnection()
def__deepcopy__(self, memo):
new_config = UserConfig()
new_config.data = copy.deepcopy(self.data, memo)
# 不拷贝 _temp_state,只保留引用或置为 None
new_config._temp_state = None
return new_config
这样才算是把问题规避掉。
顺带提一句,Python 里还有个冷门但能替代 copy 的招:copyreg 模块,可以注册自定义的拷贝行为,但写起来有点反人类,日常项目里基本没人用它……
总的来说,如果你问我什么时候该用 copy,什么时候该用 deepcopy,我一般是这么分:
如果你的数据结构比较扁平(比如只有一层 dict、list)且子元素是不可变对象,用 copy.copy()完全够了,性能高,简单。如果是多层嵌套、结构复杂且你想完全复制出来一个“隔离体”,那就用 copy.deepcopy(),不过记得看清楚有没有循环引用。如果你是自定义类,最好别偷懒,老老实实实现 __copy__和__deepcopy__。要追求极致性能?可以考虑结构化拷贝,比如 json.loads(json.dumps(obj))(适用于纯数据结构的对象)——虽然不太推荐,但有时候真快!
你们项目里有过类似的坑吗?欢迎留言讨论~
最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek
也可以看我写的这篇文章《DeepSeek满血复活,直接起飞!》来进行本地搭建。
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。