当我们在Python中处理复杂的数据结构,如列表或字典时,经常需要复制这些数据。Python提供了两种主要的复制方式:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。这两种方式在处理对象和其子对象时有所不同。
一、浅拷贝(Shallow Copy)
浅拷贝会创建一个新的对象,并将原始对象的引用地址复制到新对象中。但是,如果原始对象的元素是可变对象(例如列表、字典或其他自定义对象),则浅拷贝只会复制这些对象的引用地址,而不是实际的对象。这意味着新对象和原始对象会共享这些子对象。
1、示例
import copy
# 原始列表,包含一个子列表
original_list = [1, 2, [3, 4, 5]]
# 使用浅拷贝创建新列表
shallow_copy_list = copy.copy(original_list)
# 修改原始列表中的子列表
original_list[2][0] = 'a'
# 浅拷贝列表中的子列表也被修改了,因为它们引用的是同一个子列表
print(shallow_copy_list) # 输出:[1, 2, ['a', 4, 5]]
#浅拷贝,是指重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用。
#因此,如果原对象中的元素不可变,那倒无所谓,例如[1,2]
#但如果元素可变,如果原对象的值改变了,那么拷贝后的列表的值也会跟着修改,例如子列表[3, 4, 5]--》['a', 4, 5]
在上面的示例中,我们可以看到浅拷贝后的列表shallow_copy_list
中的子列表与原始列表original_list
中的子列表是同一个对象。因此,对原始列表中的子列表所做的修改也会影响浅拷贝列表中的子列表。
敲黑板:
新对象和原始对象会共享这些子对象。
2、业务场景
(1). 简单数据结构复制:
- 当需要复制的对象层次结构比较简单,如列表、元组、字典等,且这些对象中的元素都是不可变类型(如整数、字符串、元组等)时,浅拷贝是足够的。
- 例如,在数据处理中,可能需要复制一个包含基本数据类型的列表,以便在不改变原始数据的情况下进行操作。
(2). 引用传递:
- 在某些情况下,需要将一个对象或数组传递给函数或作为参数传递给其他对象,但不希望修改原始对象。此时,可以使用浅拷贝来传递引用,而不是复制整个对象。
- 浅拷贝可以节省内存空间,因为不需要为子对象创建新的内存空间,而只是复制引用。
(3). 缓存数据:
- 使用浅拷贝可以在不重新获取数据的情况下创建数据的副本,并在需要时使用副本。这对于避免频繁的网络请求或计算重量较大的数据很有用。
- 例如,在Web开发中,可以将经常访问但计算成本较高的数据存储在缓存中,并使用浅拷贝来创建数据的副本,以减少计算时间。
二、深拷贝(Deep Copy)
深拷贝会递归地复制对象及其所有子对象,生成一个全新的、完全独立的对象。新对象和原始对象之间没有共享的子对象。
1、示例,5,
import copy
# 原始列表,包含一个子列表
original_list = [1, 2, [3, 4, 5]]
# 使用深拷贝创建新列表
deep_copy_list = copy.deepcopy(original_list)
# 修改原始列表中的子列表
original_list[2][0] = 'a'
# 深拷贝列表中的子列表没有被修改,因为它们是独立的对象
print(deep_copy_list) # 输出:[1, 2, [3, 4, 5]]
在上面的示例中,深拷贝后的列表deep_copy_list
中的子列表与原始列表original_list
中的子列表是完全独立的对象。因此,对原始列表中的子列表所做的修改不会影响深拷贝列表中的子列表。
敲黑板:
新对象和原始对象之间没有共享的子对象。新老对象之间是完全独立的。
2、业务场景
(1). 复杂数据结构复制:
- 当需要复制的对象层次结构比较复杂,例如列表中嵌套列表、字典中嵌套字典等情况时,深拷贝是必需的。
- 深拷贝会递归地复制对象的所有子对象,确保新对象与原始对象完全独立。
(2). 确保数据独立性:
- 如果在复制后需要对数据进行修改,且这些修改不应影响原始数据,那么深拷贝是必要的。
- 例如,在算法开发中,可能需要创建原始数据的多个副本,并在每个副本上尝试不同的算法或参数设置。此时,深拷贝可以确保每个副本都是独立的,互不影响。
(3). 配置或参数管理:
- 在某些应用程序中,可能需要存储和管理多组配置或参数。使用深拷贝可以创建这些配置或参数的独立副本,以便在不干扰其他副本的情况下进行修改。
(4). 网络切片技术(Network Slicing):
- 在5G网络架构中,网络切片技术允许将网络划分为多个虚拟网络切片,每个切片可以根据不同的需求和应用场景进行独立配置和管理。深拷贝可以用于创建这些切片的独立配置副本,以确保每个切片都具有独特的配置和参数设置。
总的来说,浅拷贝适用于简单数据结构复制和引用传递的场景,而深拷贝适用于复杂数据结构复制、确保数据独立性和网络切片技术等场景。根据具体业务需求选择合适的拷贝方式可以提高程序的效率和正确性。
三、总结
- 浅拷贝只复制对象的顶层元素,如果对象中的元素是可变类型(如列表),则只复制这些子对象的引用地址,而不是引用的对象本身。
- 浅拷贝中的元素,是原对象中子对象的引用,因此,如果原对象中的元素是可变的,改变其也会影响拷贝后的对象,存在一定的副作用。
- 深度拷贝则会递归地拷贝原对象中的每一个子对象,生成一个全新的、完全独立的对象,因此拷贝后的对象和原对象互不相关。另外,深度拷贝中会维护一个字典,记录已经拷贝的对象及其ID,来提高效率并防止无限递归的发生。
在选择使用浅拷贝还是深拷贝时,需要根据具体的应用场景和需求来决定。如果对象层次结构比较简单,或者不需要复制嵌套对象,那么浅拷贝是一个高效且简单的选择。如果需要复制嵌套复杂对象,并且需要确保新对象与原始对象完全独立,那么应该使用深拷贝。
敲黑板:
深拷贝和浅拷贝最大的区别就是,要拷贝的对象是否存在子对象,并且这个子对象是可变类型的。(1,2,3,4,[5,6]),[5,6]这个就是子对象。
如果修改原始对象中的子列表,也会影响浅拷贝对象中的子列表。
如果修改原始对象中的子列表,不也会影响深拷贝对象中的子列表。