Python 之深浅 Copy
一、引言
在 Python 编程里,对数据进行复制是常见操作。不过复制存在浅复制(shallow copy)和深复制(deep copy)之分,二者有着不同的实现原理与应用场景。理解深浅复制的区别,对避免数据意外修改、优化代码性能极为关键。本文会深入剖析 Python 中深浅复制的原理,借助丰富的代码示例来加深理解。
二、浅复制(Shallow Copy)
2.1 浅复制的定义
浅复制创建一个新对象,新对象里包含的元素是原对象元素的引用。对于不可变对象,新对象和原对象引用的是同一内存地址;对于可变对象,新对象和原对象中的可变对象也指向同一内存地址。
2.2 实现浅复制的方法
2.2.1 使用切片操作
python
# 定义一个包含可变对象(列表)的列表
original_list = [1, 2, [3, 4]]
# 使用切片操作创建浅复制的列表
shallow_copy_list = original_list[:]
# 打印原始列表及其内存地址
print("原始列表:", original_list, "内存地址:", id(original_list))
# 打印浅复制列表及其内存地址
print("浅复制列表:", shallow_copy_list, "内存地址:", id(shallow_copy_list))
# 修改原始列表中的不可变元素
original_list[0] = 10
# 打印修改后原始列表
print("修改原始列表不可变元素后,原始列表:", original_list)
# 打印修改后浅复制列表
print("修改原始列表不可变元素后,浅复制列表:", shallow_copy_list)
# 修改原始列表中的可变元素
original_list[2][0] = 30
# 打印修改后原始列表
print("修改原始列表可变元素后,原始列表:", original_list)
# 打印修改后浅复制列表
print("修改原始列表可变元素后,浅复制列表:", shallow_copy_list)
在上述代码中,通过切片操作 original_list[:]
创建了浅复制列表 shallow_copy_list
。当修改原始列表中的不可变元素(如 original_list[0]
)时,浅复制列表不受影响;但当修改原始列表中的可变元素(如 original_list[2][0]
)时,浅复制列表中对应的元素也会改变,这是因为它们引用的是同一个可变对象。
2.2.2 使用 copy
模块的 copy
函数
python
import copy
# 定义一个包含可变对象(字典)的字典
original_dict = {'a': 1, 'b': {'c': 2}}
# 使用 copy 模块的 copy 函数创建浅复制的字典
shallow_copy_dict = copy.copy(original_dict)
# 打印原始字典及其内存地址
print("原始字典:", original_dict, "内存地址:", id(original_dict))
# 打印浅复制字典及其内存地址
print("浅复制字典:", shallow_copy_dict, "内存地址:", id(shallow_copy_dict))
# 修改原始字典中的不可变元素
original_dict['a'] = 10
# 打印修改后原始字典
print("修改原始字典不可变元素后,原始字典:", original_dict)
# 打印修改后浅复制字典
print("修改原始字典不可变元素后,浅复制字典:", shallow_copy_dict)
# 修改原始字典中的可变元素
original_dict['b']['c'] = 20
# 打印修改后原始字典
print("修改原始字典可变元素后,原始字典:", original_dict)
# 打印修改后浅复制字典
print("修改原始字典可变元素后,浅复制字典:", shallow_copy_dict)
此代码使用 copy.copy()
函数对字典进行浅复制。和切片操作类似,修改原始字典中的不可变元素不影响浅复制字典,而修改可变元素会同时改变浅复制字典中的对应元素。
三、深复制(Deep Copy)
3.1 深复制的定义
深复制会递归地复制原对象及其所有嵌套的对象,创建一个完全独立的新对象。新对象和原对象在内存中是完全分离的,对新对象的任何修改都不会影响原对象,反之亦然。
3.2 实现深复制的方法
使用 copy
模块的 deepcopy
函数。
python
import copy
# 定义一个包含多层嵌套可变对象的列表
original_nested_list = [1, [2, [3, 4]]]
# 使用 copy 模块的 deepcopy 函数创建深复制的列表
deep_copy_list = copy.deepcopy(original_nested_list)
# 打印原始嵌套列表及其内存地址
print("原始嵌套列表:", original_nested_list, "内存地址:", id(original_nested_list))
# 打印深复制列表及其内存地址
print("深复制列表:", deep_copy_list, "内存地址:", id(deep_copy_list))
# 修改原始嵌套列表中的可变元素
original_nested_list[1][1][0] = 30
# 打印修改后原始嵌套列表
print("修改原始嵌套列表可变元素后,原始嵌套列表:", original_nested_list)
# 打印修改后深复制列表
print("修改原始嵌套列表可变元素后,深复制列表:", deep_copy_list)
在这个代码中,使用 copy.deepcopy()
函数对多层嵌套的列表进行深复制。当修改原始嵌套列表中的可变元素时,深复制列表不受影响,因为它们是完全独立的对象。
四、浅复制与深复制的应用场景
4.1 浅复制的应用场景
浅复制适用于仅需复制对象的顶层结构,且不希望创建过多对象占用大量内存的情况。例如,在数据展示或简单的数据传递中,若不需要对嵌套对象进行修改,使用浅复制可以节省内存。
4.2 深复制的应用场景
深复制适用于需要完全独立于原对象的情况,以避免因对象引用而导致的数据意外修改。例如,在多线程编程中,为了防止不同线程对同一对象进行修改产生冲突,可使用深复制创建独立的对象副本。
五、总结与展望
5.1 总结
Python 中的浅复制和深复制是两种不同的数据复制方式。浅复制只复制对象的顶层结构,对于嵌套的可变对象,新对象和原对象共享引用;深复制则递归地复制所有嵌套对象,创建完全独立的新对象。在实际编程中,应根据具体需求选择合适的复制方式,避免数据意外修改和不必要的内存开销。
5.2 展望
随着 Python 在数据处理、机器学习等领域的广泛应用,对数据复制的效率和准确性要求会越来越高。未来可能会有更高效的深浅复制算法和实现方式出现,同时也需要开发者更加深入地理解和运用这些概念,以提高代码的性能和可靠性。