deepcopy 与 copy 的本质区别——是否为可变对象创建新的对象(内存空间)
以下图片截取自Python Tutorial
代码片段一
- 可变对象 list 中包含着可变 list 和不可变对象 tuple,且 tuple 中不包含可变对象
1
2
3
4
5import copy
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1) # <==> l2 = copy.copy(l1)
# <==> l2 = l1[:]
l3 = copy.deepcopy(l1)
代码片段二
- 可变对象 list 中包含着可变 list 和不可变对象 tuple, 且tuple中包含可变对象list
1
2
3
4
5import copy
l1 = [3, [66, 55, 44], (7, 8, [1, 2])]
l2 = list(l1) # <==> l2 = copy.copy(l1)
# <==> l2 = l1[:]
l3 = copy.deepcopy(l1)
代码片段三
- 不可变对象中包含可变对象
- 值得强调的是,copy 复制 tuple时,不会像 list 那样直接创建新对象,无论 tuple 中是否有可变对象
- 除非包含不可变对象,否则 deepcopy 复制 tuple 时也不会创建新对象
1
2
3
4
5
6
7import copy
t1 = (3, [66, 55, 44], (7, 8, [1, 2]))
t2 = t1
t3 = tuple(t1) # <==> t4 = t1[:]
# t5 = copy.copy(t1)
t6 = copy.deepcopy(t1)
t1[1].append(100)
copy和deepcopy直接对比
copy.copy()是浅拷贝,copy.deepcopy()是深拷贝
浅拷贝 (copy.copy())
当你使用 copy.copy() 函数时,它会创建一个新对象,然后将原始对象中包含的所有元素引用都复制到这个新对象中。这意味着如果你修改了原对象中的可变元素(如列表、字典等),那么副本中的这些元素也会受到影响,因为它们实际上是指向同一个内存位置的引用
浅拷贝示例:
1
2
3
4
5
6
7import copy
original_list = [[1, 2], [3, 4]]
shallow_copy = copy.copy(original_list)
original_list[0][0] = 'changed'
print(original_list) # 输出: [['changed', 2], [3, 4]]
print(shallow_copy) # 输出: [['changed', 2], [3, 4]]- 在这个例子中,对
original_list的修改也影响到了shallow_copy,因为子列表是被引用的,而不是被复制的
- 在这个例子中,对
深拷贝 (copy.deepcopy())
copy.deepcopy()函数则不仅复制了对象本身,还递归地复制了对象中包含的所有对象。因此,新的对象及其包含的所有对象都是完全独立的,对原对象或其内部对象的任何改变都不会影响到深拷贝后的对象深拷贝示例:
1
2
3
4
5
6
7import copy
original_list = [[1, 2], [3, 4]]
deep_copy = copy.deepcopy(original_list)
original_list[0][0] = 'changed'
print(original_list) # 输出: [['changed', 2], [3, 4]]
print(deep_copy) # 输出: [[1, 2], [3, 4]]- 在这个例子中,对
original_list的修改不会影响到deep_copy,因为所有级别的对象都被复制了
- 在这个例子中,对
总结
- 对于不可变对象调用 deepcopy 和 copy 函数时:
- deepcopy 与 copy 操作一样,都不为创建新对象,而是直接引用
- 在后面如果有修改该不可变对象的操作时再创建新对象,此时两个版本的不可变对象地址变得不同
- 这里是 Python 的常态,比如
tuple(tuple1)将返回一个 tuple1 对象的引用而不是副本,当修改 tuple1 时才会创建新对象 - 因为无论如何,修改不可变对象的不可变部分都不会修改原始对象,所以为了节约内存,Python 解释器完全可以将创建新对象延后到修改内容时
- 对于可变对象调用 deepcopy 和 copy 函数时:
- 使用
copy.copy()只复制对象的第一层,对于对象内部的嵌套对象只复制引用 - 使用
copy.deepcopy()会递归地复制整个对象结构,包括所有的嵌套对象,从而确保两个对象完全独立。
- 使用