在 Python 开发中,我们常常希望复制一个对象,以避免直接修改原始数据。然而,“复制”这个操作远没有看起来那么简单。Python 提供了两种常见的复制方式:浅拷贝(shallow copy)和 深拷贝(deep copy),它们在处理嵌套对象时行为大不相同。

这篇博客会一步步解释它们之间的区别、使用场景,以及如何避免常见的坑。


赋值 ≠ 复制

先看一个简单例子:

a = [1, 2, 3]
b = a
b[0] = 100
print(a) # [100, 2, 3]

这里的 b = a 并没有复制 a,而是使 b 指向 a 的同一个内存地址,两者是同一个对象


浅拷贝 (shallow copy)

import copy

a = [1, [2, 3]]
b = copy.copy(a)

b[0] = 100
b[1][0] = 200

print("a:", a) # [1, [200, 3]]
print("b:", b) # [100, [200, 3]]

浅拷贝特点

  • 创建了一个新对象,但只复制了第一层结构

  • 内部嵌套对象仍然引用原始对象

  • 修改嵌套部分,原始对象会受到影响

    常用于简单结构或不打算修改嵌套部分的场景


深拷贝 (deep copy)

import copy

a = [1, [2, 3]]
b = copy.deepcopy(a)

b[0] = 100
b[1][0] = 200

print("a:", a) # [1, [2, 3]]
print("b:", b) # [100, [200, 3]]

深拷贝特点

  • 递归复制所有层级的对象,生成完全独立的新对象

  • 原始对象和复制对象互不影响

  • 安全但性能较慢,适用于复杂对象

    常用于保存快照、传递副本或避免副作用时


实战示例:字典中的 copy

original = {"user": "Alice", "settings": {"theme": "dark"}}
shallow = copy.copy(original)
deep = copy.deepcopy(original)

shallow["settings"]["theme"] = "light"
print(original["settings"]["theme"]) # light

虽然 shallow 是新对象,但它里面的 settings 字典依然与 original 共享,因此修改会同步到原始对象。


使用建议:如何判断用哪种?

拷贝类型 是否递归 嵌套对象独立性 推荐场景
浅拷贝 简单结构、追求效率
深拷贝 嵌套结构、追求安全

判断建议:

  • 如果你确定不会修改嵌套内容:✅ 用浅拷贝
  • 如果你要修改副本、保护原始数据:✅ 用深拷贝
  • 如果你的对象非常复杂(如嵌套 dict / list / 自定义类):✅ 推荐深拷贝

常见误区

  • 误以为 = 是复制:它只是引用
  • 误以为 copy.copy 是完全独立副本:嵌套部分仍共享
  • 过度使用深拷贝:虽然安全,但会牺牲性能,特别是在大型数据结构中

总结

  • 拷贝是避免副作用的重要手段,但要选对工具
  • 浅拷贝只复制第一层结构,适合简单对象
  • 深拷贝递归复制全部内容,适合复杂场景
  • 使用 copy.copy()copy.deepcopy() 要清楚你的数据结构

参考内容: