浅复制(shallow copy) 创建一个新的顶层对象,但嵌套对象(列表元素、嵌套字典等)与原始对象共享内存。深复制(deep copy) 递归地复制所有层次的对象。
可以通过 copy 模块使用:
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # 同时改变 original 和 shallow print(original) # [[99, 2], [3, 4]] # 现在使用 deep original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]
copy.copy(obj):仅复制 "外壳"copy.deepcopy(obj):完全递归复制复制包含可变对象的元组会发生什么?
tuple 是不可变的,但其元素可以是可变的(例如,列表)。浅复制和深复制有所不同:
import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # 深复制时: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])
故事
在处理文档的应用程序中,数据存储在字典中的列表中。通过 copy.copy 复制对象时,嵌套元素在修改新对象时意外改变,最终导致系统其他部分的原始数据被更改!发生了数据损坏。最终通过使用 deepcopy 修复。
故事
在一个机器学习项目中,保存模型的超参数时通过标准赋值和浅复制复制配置列表,不同实验之间的参数互相影响。通过诊断嵌套列表使用深复制的行为找到了 bug 的来源。
故事
在金融软件中,深复制意外应用于包含打开文件(句柄)的对象,导致 TypeError: cannot pickle '_io.TextIOWrapper' object — 因为 copy.deepcopy 在幕后使用 pickle。通过明确处理这些字段或调用浅复制来修复。