进来了解一下python的深浅拷贝

Python 中的深拷贝(deep copy)浅拷贝(shallow copy) 是非常容易混淆但又极其重要的一对概念,尤其在处理嵌套的可变对象(list、dict、set 等)时,一不小心就会出现“改一个地方,另一个地方也变了”的 bug。

下面用最直白的方式 + 代码 + 内存图思路帮你彻底搞懂(2026 年最新写法也没变化,核心机制从 Python 2.x 到 3.12+ 都一样)。

一、先搞清楚三种“复制”方式的区别

方式写法是否创建新对象嵌套对象是否共享引用修改嵌套对象是否互相影响适用场景
直接赋值b = a共享只是想多个名字指向同一个对象
浅拷贝copy.copy()a[:] / list(a) / dict(a)共享只想复制最外层,内层可以共享
深拷贝copy.deepcopy()不共享(递归复制)想要完全独立的两份数据

二、经典代码对比(强烈建议你自己敲一遍)

import copy

# ----------------- 准备数据 -----------------
original = [1, 2, [3, 4], {"name": "重阳"}]

# 方式1:直接赋值(最容易出错的新手写法)
a1 = original
a1[2][0] = 999
print(original)     # [1, 2, [999, 4], {'name': '重阳'}]   ← 原数据也被改了!

# 方式2:浅拷贝(常见面试题考察点)
a2 = copy.copy(original)           # 或 a2 = original[:] / list(original)
a2[2][0] = 888
print(original)     # [1, 2, [888, 4], {'name': '重阳'}]   ← 嵌套列表还是被改了!
print(a2)           # [1, 2, [888, 4], {'name': '重阳'}]

a2[0] = 777         # 修改最外层
print(original[0])  # 还是 1(外层不共享)

# 方式3:深拷贝(真正独立)
a3 = copy.deepcopy(original)
a3[2][0] = 666
a3[3]["name"] = "Grok"
print(original)     # [1, 2, [888, 4], {'name': '重阳'}]   ← 原数据完全不动!
print(a3)           # [1, 2, [666, 4], {'name': 'Grok'}]

三、用内存图直观理解(面试/debug 神器)

原始对象:
original ──► [1, 2, 列表A, 字典B]
                    ▲         ▲
                    │         │
                    └─────┬───┘
                          │
浅拷贝 a2 ──► [新列表]     │  ← 外层是新的,内层指向同一个列表A 和 字典B
                          │
深拷贝 a3 ──► [全新列表] ──┼─► [全新 666, 4]   ← 所有层级都重新创建
                          └─► [全新 {"name":"Grok"}]

四、常见实现浅拷贝的方式(面试常考)

lst = [[1,2], [3,4]]

# 以下都是浅拷贝
shallow1 = lst[:]                  # 切片
shallow2 = list(lst)               # 构造器
shallow3 = copy.copy(lst)
shallow4 = lst.copy()              # Python 3.3+ 列表自带方法(推荐)

# 字典同理
d = {"a": [1,2]}
shallow_d = d.copy()               # 字典自带浅拷贝

五、深拷贝的特殊情况 & 坑(2026 年仍需注意)

  1. 循环引用(自己包含自己)
   a = [1, 2]
   a.append(a)          # a 包含了自己
   b = copy.deepcopy(a) # 能正确处理循环引用,不会无限递归
  1. 自定义类(需要实现 __copy__ / __deepcopy__ 才能完美拷贝)
  • 普通类默认浅拷贝只复制引用
  • 深拷贝会递归调用对象的 __deepcopy__(如果没实现就用默认行为)
  1. 函数、模块、文件对象 等不可序列化的东西
  • deepcopy 会报错或返回原对象(视情况)
  1. 性能:深拷贝非常慢,尤其是大数据结构 → 优先考虑是否真的需要深拷贝

六、总结一句话口诀(背下来就不会错)

  • 想改外层不影响原对象 → 浅拷贝就够(最常用)
  • 想改里层也不影响原对象 → 必须深拷贝
  • 只是多个变量指向同一个东西 → 直接用 =

最实用建议

  • 99% 的业务场景用 .copy()list() / dict() 就够了
  • 真正需要完全独立副本(比如配置模板、测试数据)才上 deepcopy
  • 调试时多用 id() 查看对象是否相同:id(a[2]) == id(original[2])

有哪部分还觉得模糊?
想看更多例子(比如嵌套多层字典、自定义类拷贝、deepcopy 性能对比)?
或者想直接来几道面试题练手?随时说,我继续陪你过这一关。

文章已创建 5245

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部