🐍Python 语言基础
浅拷贝与深拷贝
面试回答
常见问法
浅拷贝和深拷贝有什么区别?为什么 Python 里这个问题经常和可变对象一起问?
回答
浅拷贝只复制最外层对象,内部嵌套元素仍然共享;深拷贝会递归复制内部对象,尽量得到完全独立的新结构。
import copy
data = [[1, 2], [3, 4]]
a = copy.copy(data) # 浅拷贝
b = copy.deepcopy(data) # 深拷贝
data[0].append(99)
print(f"原对象: {data}") # [[1, 2, 99], [3, 4]]
print(f"浅拷贝: {a}") # [[1, 2, 99], [3, 4]] # 受影响!
print(f"深拷贝: {b}") # [[1, 2], [3, 4]] # 不受影响
追问
list[:]、list()、copy.copy()都算什么拷贝?(都是浅拷贝)- 为什么深拷贝更安全但也更贵?(递归开销、循环引用处理)
- 自定义对象的深拷贝行为能不能控制?(
__deepcopy__方法)
原理展开
浅拷贝复制的是容器壳,不复制内部引用指向的对象。
nums = [[1], [2]]
nums2 = nums[:] # 切片浅拷贝
nums[0].append(10)
print(f"nums: {nums}") # [[1, 10], [2]]
print(f"nums2: {nums2}") # [[1, 10], [2]] # 受影响!
# 深拷贝会递归处理
nums3 = copy.deepcopy(nums)
nums[0].append(20)
print(f"nums: {nums}") # [[1, 10, 20], [2]]
print(f"nums3: {nums3}") # [[1, 10], [2]] # 不受影响
# 常见的浅拷贝方法
list1 = [1, 2, 3]
shallow1 = list1.copy() # 方法1
shallow2 = list1[:] # 方法2(切片)
shallow3 = list(list1) # 方法3(构造函数)
shallow4 = copy.copy(list1) # 方法4
# 所有浅拷贝方法都创建新容器
print(f"都是不同对象: {all(list1 is s for s in [shallow1, shallow2, shallow3, shallow4])}") # False
# 但内部元素共享
nested = [[1], [2]]
shallow_nested = nested.copy()
print(f"内部元素共享: {nested[0] is shallow_nested[0]}") # True
# 自定义对象的深拷贝控制
class Config:
def __init__(self, data):
self.data = data
def __deepcopy__(self, memo):
# 控制深拷贝行为
copied = Config(copy.deepcopy(self.data, memo))
return copied
config = Config({'key': [1, 2, 3]})
config_copy = copy.deepcopy(config)
config.data['key'].append(4)
print(f"原配置: {config.data}") # {'key': [1, 2, 3, 4]}
print(f"拷贝配置: {config_copy.data}") # {'key': [1, 2, 3]}
面试里最好把它和业务场景挂钩:
- 配置模板复制
- 多层嵌套 JSON 结构复制
- 默认参数里放可变对象导致共享状态
易错点
- 以为切片复制就是完全独立副本(实际是浅拷贝)
- 不区分”外层新对象”和”内部元素是否共享”
- 深拷贝一切对象时忽略性能和循环引用成本
- 在不需要独立副本时使用深拷贝(性能浪费)
记忆技巧
记住拷贝的区别:
- 浅拷贝 = “复制容器,共享内容”
- 深拷贝 = “递归复制所有内容”
常见拷贝方法分类:
- 浅拷贝:
list.copy(),list[:],list(),copy.copy(), 列表推导式 - 深拷贝:
copy.deepcopy(), 自定义__deepcopy__
典型应用场景:
- 浅拷贝:简单列表、不需要嵌套独立、性能敏感
- 深拷贝:嵌套结构、配置复制、需要完全独立、避免副作用
性能考虑:
- 浅拷贝:O(n) 时间复杂度
- 深拷贝:O(n) + 递归开销,可能处理循环引用
- 不可变对象:浅拷贝和深拷贝效果相同