编程数据工程师

解释浅复制(shallow copy)和深复制(deep copy)之间的区别,以及在复制复杂对象时 copy.copy 和 copy.deepcopy 的行为。请举例说明错误理解导致的 bug。

用 Hintsage AI 助手通过面试

答案。

浅复制(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。通过明确处理这些字段或调用浅复制来修复。