深入理解 Python 中的对象赋值、浅拷贝与深拷贝
在 Python 中,处理对象及其副本时,存在三种核心机制:直接赋值、浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。理解它们在内存管理和对象引用上的差异,对于编写健壮的代码至关重要。
1. 对象赋值
赋值操作实际上是创建了一个新的引用,指向内存中已存在的同一个对象。无论是修改原变量还是新变量,操作的都是同一个内存空间。
# 示例:列表赋值
original_list = [10, 20, [30, 40]]
assigned_list = original_list
print(original_list is assigned_list) # True
assigned_list.append(50)
print(original_list) # [10, 20, [30, 40], 50]
对于不可变类型(如字符串、元组),赋值后如果尝试修改,Python 会创建一个新对象,此时引用地址会发生变化。
2. 浅拷贝
浅拷贝会创建一个新对象,但该对象内部的元素如果是引用类型,则仍然指向原对象中子对象的内存地址。即只拷贝"父"对象,不拷贝"子"对象。
2.1 实现方式
- 使用数据类型构造函数:
list(),dict(),set() - 使用切片操作:
[:] - 使用
copy模块的copy()函数
2.2 可变对象与不可变对象的差异
import copy
# 可变对象:地址会改变
base_nums = [1, 2, 3]
shallow_nums = copy.copy(base_nums)
print(base_nums is shallow_nums) # False
# 不可变对象:地址通常保持一致(Python 内部优化机制)
base_tuple = (1, 2, 3)
shallow_tuple = copy.copy(base_tuple)
print(base_tuple is shallow_tuple) # True
2.3 嵌套结构的陷阱
在处理嵌套列表时,浅拷贝无法隔离子列表的修改:
nested_data = ["a", "b", [1, 2]]
shallow_data = nested_data[:]
shallow_data[2].append(3)
print(nested_data) # ['a', 'b', [1, 2, 3]]
print(shallow_data) # ['a', 'b', [1, 2, 3]]
3. 深拷贝
深拷贝会递归地拷贝对象及其所有层级的子对象。拷贝完成后,新对象与原对象在内存上完全独立,互不影响。
3.1 实现方式
通过 copy.deepcopy() 实现:
import copy
complex_list = [5, 6, [7, 8]]
deep_cloned = copy.deepcopy(complex_list)
deep_cloned[2].append(9)
print(complex_list) # [5, 6, [7, 8]]
print(deep_cloned) # [5, 6, [7, 8, 9]]
print(complex_list[2] is deep_cloned[2]) # False
3.2 特殊情况
对于不可变类型(如元组),如果元组内部只包含不可变元素,deepcopy 为了节省内存,可能仍会返回原对象的引用。
pure_tuple = (1, 2, 3)
deep_tuple = copy.deepcopy(pure_tuple)
print(pure_tuple is deep_tuple) # True
总结对比
| 操作 | 父对象地址 | 子对象地址 | 修改子对象影响原对象 |
|---|---|---|---|
| 赋值 | 相同 | 相同 | 是 |
| 浅拷贝 | 不同 | 相同 | 是 |
| 深拷贝 | 不同 | 不同 | 否 |