Python 中深拷贝和浅拷贝有什么区别?
核心区别
赋值(=) | 浅拷贝(copy) | 深拷贝(deepcopy) | |
|---|---|---|---|
| 新对象 | ❌ 同一对象 | ✅ 新的外层对象 | ✅ 新的所有层对象 |
| 内层对象 | 共享 | 共享 | 完全独立 |
| 内存开销 | 最小 | 小 | 最大 |
图解
原始列表: a = [[1, 2], [3, 4]]
赋值 b = a
a ──► [ ref1, ref2 ]
b ──► [ ref1, ref2 ] ← 同一个对象
浅拷贝 b = copy.copy(a)
a ──► [ ref1, ref2 ]
b ──► [ ref1, ref2 ] ← 新列表,但内层 ref1/ref2 共享
深拷贝 b = copy.deepcopy(a)
a ──► [ ref1, ref2 ]
b ──► [ ref1', ref2' ] ← 完全独立的新对象
代码示例
import copy
original = [[1, 2], [3, 4]]
# 赋值
assigned = original
# 浅拷贝
shallow = copy.copy(original)
# 深拷贝
deep = copy.deepcopy(original)
# 修改内层元素
original[0][0] = 99
print(original) # [[99, 2], [3, 4]]
print(assigned) # [[99, 2], [3, 4]] ← 受影响(同一对象)
print(shallow) # [[99, 2], [3, 4]] ← 受影响(内层共享)
print(deep) # [[1, 2], [3, 4]] ← 不受影响
# 修改外层(添加元素)
original.append([5, 6])
print(assigned) # [[99, 2], [3, 4], [5, 6]] ← 受影响
print(shallow) # [[99, 2], [3, 4]] ← 不受影响(外层独立)
print(deep) # [[1, 2], [3, 4]] ← 不受影响
浅拷贝的多种写法
lst = [1, [2, 3]]
import copy
a = copy.copy(lst) # 通用方式
b = lst[:] # 切片(仅限列表)
c = list(lst) # 构造函数
d = lst.copy() # 列表方法
# 以上四种等价,都是浅拷贝
不可变对象的特殊情况
对于 int、str、tuple(不含可变元素)等不可变对象,浅拷贝和深拷贝没有实际差异,Python 通常直接复用同一对象:
import copy
a = (1, 2, 3)
b = copy.copy(a)
c = copy.deepcopy(a)
print(a is b) # True ← 不可变对象直接复用
print(a is c) # True
但包含可变元素的元组仍需注意:
a = ([1, 2], [3, 4])
b = copy.copy(a)
c = copy.deepcopy(a)
a[0][0] = 99
print(b[0]) # [99, 2] ← 浅拷贝内层共享
print(c[0]) # [1, 2] ← 深拷贝完全独立
自定义深拷贝行为
通过实现 __copy__ 和 __deepcopy__ 方法控制拷贝逻辑:
class MyObj:
def __init__(self, data):
self.data = data
def __deepcopy__(self, memo):
new_obj = MyObj(copy.deepcopy(self.data, memo))
memo[id(self)] = new_obj
return new_obj
性能考量
deepcopy 会递归复制所有嵌套对象,对于复杂对象图可能较慢。替代方案:
import json
# 对纯 JSON 兼容结构,序列化再反序列化速度更快
deep_copy = json.loads(json.dumps(original))
总结
- 赋值
=:不创建新对象,两个变量指向同一份数据 - 浅拷贝:创建新的外层容器,内层对象仍共享——修改内层会互相影响
- 深拷贝:递归复制所有层级,完全独立——互不影响
- 选型原则:数据结构只有一层或元素为不可变类型时用浅拷贝;有嵌套可变对象且需要完全隔离时用深拷贝