深浅拷贝
【一】深浅拷贝问题的引入
-
无论是深拷贝还是浅拷贝都是用来复制对象用的
-
如果是浅拷贝,只会复制一层,如果拷贝的对象是可变数据类型,修改可变数据类型还会影响拷贝的对象
-
在python中,深拷贝和浅拷贝是用于复制对象不同的两种方式
list_original = [1, 2, 3, [4, 5, 6, ]] list_copy = list_original print(list_copy is list_original) # True
-
通过将
list_copy
赋值为list_original
,实际上是将list_copy
和list_original
指向相同的内存地址。 -
所以
list_copy is list_original
的结果为True,表示它们是同一个对象的两个引用。 -
因此对
list_copy
或list_original
的修改都会影响到另一个。
【1】浅拷贝
-
浅拷贝仅复制对象的一层内容,如果对象中包含了可变数据类型,拷贝的对象将与原对象共享内存地址
-
这意味这两方任意一方发生改变时,另一方都会都到影响
import copy original_list = [1, 2, 3, [1, 2]] # 使用浅拷贝创建拷贝对象 cope_list = copy.copy(original_list) original_list[3].append(4) print(original_list) # [1, 2, 3, [1, 2, 4]] print(cope_list) # [1, 2, 3, [1, 2, 4]] print(cope_list is original_list) # False
-
可以发现当我修改了原函数之后
-
拷贝的内容也随之修改了
-
但是两者指向不同的内存地址
(2)深拷贝
- 深拷贝会创建一个完全独立的新对象,包括所有的嵌套对象。
- 无论原对象的数据类型是可变还是不可变,深拷贝都会创建出新的对象,以后对原对象的修改不会影响到拷贝对象。
- 以下是一个使用深拷贝的案例:
import copy
# 原对象
original_list = [1, 2, [3, 4]]
# 使用深拷贝创建拷贝对象
copied_list = copy.deepcopy(original_list)
# 修改原对象中的可变数据类型
original_list[2].append(5)
print("原对象:", original_list)
print("拷贝对象:", copied_list)
- 可以看到,尽管修改了原对象中的可变数据类型,但拷贝对象保持不变。
- 这是因为深拷贝创建了一个原对象完全独立的新对象,包括了所有嵌套对象的复制。
from copy import deepcopy
list_original = [1, 2, 3, [4, 5, 6, ]]
list_deep_copy = deepcopy(list_original)
list_deep_copy[3][1] = 888
print(list_original)
# [1, 2, 3, [4, 5, 6]]
print(list_deep_copy)
# [1, 2, 3, [4, 888, 6]]
- 通过使用
deepcopy()
函数进行深拷贝,会递归地复制嵌套对象,包括嵌套列表。 - 这意味着在深拷贝操作中不仅会创建一个新的顶层列表对象
list_deep_copy
,还会创建一个新的嵌套列表对象,并且其值与原始列表中的值相同。 - 因此在对
list_deep_copy
中的嵌套列表进行修改时,并不会影响到原始的列表list_original
,它们指向不同的内存地址。
(3)小结
- 综上所述
- 浅拷贝只复制顶层对象
- 而深拷贝会递归复制整个对象结构。
- 在涉及到可变对象嵌套的情况下
- 深拷贝是一种更安全的选项
- 因为它可以确保对新对象的修改不会影响原始对象。
【二】深浅拷贝问题详解
- 深拷贝和浅拷贝是常用的操作,它们在处理对象和数据结构时非常有用。
- 让我们详细解释深拷贝和浅拷贝的概念,并结合案例进行演示。
(1)深拷贝:
- 深拷贝是指创建一个新的对象,该对象与原始对象完全独立。
- 换句话说,它会递归地复制所有嵌套对象,包括它们的内容,以便我们在修改新对象时不会影响到原始对象。
- 下面是一个示例
- 演示了如何使用
copy
模块中的deepcopy()
函数进行深拷贝:
- 演示了如何使用
import copy
list1 = [1, 2, [3, 4]]
list2 = copy.deepcopy(list1)
- 在这个例子中,我们创建了一个列表
list1
,其中包含一个嵌套列表。 - 通过调用
deepcopy()
函数并将list1
作为参数传递给它,我们可以创建一个名为list2
的新对象,它是list1
的深拷贝。 - 现在,我们来演示深拷贝是如何避免原始对象的修改的:
list2[0] = 999
print(list1) # 输出: [1, 2, [3, 4]]
print(list2) # 输出: [999, 2, [3, 4]]
- 可以看到,尽管我们修改了
list2
的第一个元素,但list1
保持不变。 - 这是因为
list1
和list2
是独立的对象,它们各自占用着不同的内存空间。
(2)浅拷贝:
- 浅拷贝是指创建一个新对象,并将原始对象的元素复制到新对象中。
- 然而
- 如果原始对象包含可变的对象(如列表)
- 则新对象中的这些元素仍然与原始对象中相应元素共享相同的内存地址。
- 下面是一个示例
- 演示了如何使用
copy
模块中的copy()
函数进行浅拷贝:
- 演示了如何使用
import copy
list1 = [1, 2, [3, 4]]
list2 = copy.copy(list1)
- 在这个例子中
- 我们使用
copy()
函数创建了list1
的浅拷贝list2
。
- 我们使用
- 让我们来看一下浅拷贝在修改可变对象时的行为:
list2[0] = 999
list2[2][0] = 777
print(list1) # 输出: [1, 2, [777, 4]]
print(list2) # 输出: [999, 2, [777, 4]]
- 可以看到
- 当我们修改
list2
中的第一个元素时 - 只有
list2
受到影响 - 而
list1
保持不变。
- 当我们修改
- 但是
- 当我们修改
list2
中嵌套列表的元素时 list1
也会随之改变。
- 当我们修改
- 这是因为浅拷贝只复制了列表的引用
- 而没有创建新的内存空间来存储嵌套列表。
(3)综上所述
- 深拷贝和浅拷贝在处理对象和数据结构时有不同的行为:
- 深拷贝创建一个完全独立的对象,递归地复制所有嵌套对象。
- 浅拷贝创建一个新对象,但它共享原始对象中可变对象的引用。