🐍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 结构复制
  • 默认参数里放可变对象导致共享状态

易错点

  • 以为切片复制就是完全独立副本(实际是浅拷贝)
  • 不区分”外层新对象”和”内部元素是否共享”
  • 深拷贝一切对象时忽略性能和循环引用成本
  • 在不需要独立副本时使用深拷贝(性能浪费)

记忆技巧

记住拷贝的区别:

  1. 浅拷贝 = “复制容器,共享内容”
  2. 深拷贝 = “递归复制所有内容”

常见拷贝方法分类:

  • 浅拷贝list.copy(), list[:], list(), copy.copy(), 列表推导式
  • 深拷贝copy.deepcopy(), 自定义 __deepcopy__

典型应用场景:

  • 浅拷贝:简单列表、不需要嵌套独立、性能敏感
  • 深拷贝:嵌套结构、配置复制、需要完全独立、避免副作用

性能考虑:

  • 浅拷贝:O(n) 时间复杂度
  • 深拷贝:O(n) + 递归开销,可能处理循环引用
  • 不可变对象:浅拷贝和深拷贝效果相同