概述
本文主要通过两个简单的代码小例子理解深拷贝和浅拷贝
主体内容
copy 模块提供了浅拷贝和深拷贝的功能。它的主要函数有:
copy(x)
: 返回对象 x 的浅拷贝。
deepcopy(x)
: 返回对象 x 的深拷贝。
浅拷贝使用 copy(x)
函数,它只复制了最外层的对象,但内层的对象仍然是引用。此外当我们使用切片操作 [:]
、工厂函数如 list()
或copy
模块时,也是使用的浅拷贝,尽管我们创建了一个新的对象,它有自己的内存空间。但是,如果原始对象包含其他对象的引用(如列表中的列表,字典中的列表等),那么新对象和原始对象将共享这些内层对象的同一引用。
让我们通过一个例子来理解这一点:
original_list = [1, 2, [3, 4]]
new_list = original_list[:] # 使用切片操作进行浅拷贝
print(original_list) # 输出: [1, 2, [3, 4]]
print(new_list) # 输出: [1, 2, [3, 4]]
# 修改原始列表的第一个元素
original_list[0] = 100
print(original_list) # 输出: [100, 2, [3, 4]]
print(new_list) # 输出: [1, 2, [3, 4]]
# 修改原始列表中内层列表的第一个元素
original_list[2][0] = 300
print(original_list) # 输出: [100, 2, [300, 4]]
print(new_list) # 输出: [1, 2, [300, 4]]
在这个例子中:
我们首先创建了一个列表 original_list
,其中包含两个整数和一个内层列表。
我们使用切片操作 [:]
创建了 original_list
的浅拷贝 new_list
。
然后我们修改original_list
的第一个元素。我们发现 new_list
没有受到影响,因为它是一个独立的对象。
但是,当我们修改 original_list
中内层列表的第一个元素时,我们发现 new_list
中的内层列表也被修改了。这是因为 new_list
和 original_list
共享了内层列表的同一引用。
所以,浅拷贝创建了一个新的对象,但如果原始对象包含其他对象的引用,那么新对象和原始对象将共享这些引用。对原始对象的外层修改不会影响新对象,但对内层对象的修改会影响新对象,因为它们共享同一引用。
如果你想创建一个完全独立的副本,包括内层对象,你需要使用深拷贝(deep copy)。在 Python 中,你可以使用copy
模块的deepcopy()
函数来创建深拷贝。
深拷贝使用 deepcopy(x)
函数,它创建一个新的复合对象,然后递归地插入原始对象中的对象的副本。这意味着深拷贝也复制了内层对象,深拷贝才是真正意义上我们理解的复制,全须全尾地开辟了一个内存空间复制了一遍。
import copy
original_list = [1, 2, [3, 4]]
new_list = copy.deepcopy(original_list) # 使用 deepcopy() 函数进行深拷贝
print(original_list) # 输出: [1, 2, [3, 4]]
print(new_list) # 输出: [1, 2, [3, 4]]
# 修改原始列表的第一个元素
original_list[0] = 100
print(original_list) # 输出: [100, 2, [3, 4]]
print(new_list) # 输出: [1, 2, [3, 4]]
# 修改原始列表中内层列表的第一个元素
original_list[2][0] = 300
print(original_list) # 输出: [100, 2, [300, 4]]
print(new_list) # 输出: [1, 2, [3, 4]]
一句话总结
在大多数情况下,如果你的对象只包含原始数据类型或只有一层嵌套,你可以使用浅拷贝。但如果你的对象包含多层嵌套或可变对象,为了确保完全的独立性,你应该使用深拷贝。