Python 中以 copy.deepcopy() 来实现对象的深度拷贝
import copy
list1 = [[1, 2], (30, 40)]
list2 = copy.deepcopy(list1)
list1.append(100)
print("list1:",list1)
print("list2:",list2)
list1[0].append(3)
print("list1:",list1)
print("list2:",list2)
list1[1] += (50, 60)
print("list1:",list1)
print("list2:",list2)
list1: [[1, 2], (30, 40), 100]
list2: [[1, 2], (30, 40)]
list1: [[1, 2, 3], (30, 40), 100]
list2: [[1, 2], (30, 40)]
list1: [[1, 2, 3], (30, 40, 50, 60), 100]
list2: [[1, 2], (30, 40)]
浅拷贝创建一个新的复合对象,然后(通过引用)将原始对象中的子对象放入新对象中。这意味着,如果原始对象中的某个元素是可变的(如列表、字典等),那么拷贝后的新对象中的相应元素仍然是原始元素的引用,而非其独立副本。因此,对于这些共享的子对象所做的任何非就地(non-in-place)修改都会反映到所有引用这些子对象的对象中。深拷贝与浅拷贝相反,它不仅创建了一个新的复合对象,而且递归地创建了原始对象中所有子对象的副本。因此,深拷贝后的对象与原始对象完全独立,对任一对象的修改都不会影响到另一个。
浅拷贝:复制对象,但嵌套对象仍然引用原对象中的子对象。深拷贝:复制对象,包括所有嵌套的子对象,使得新对象与原对象完全独立。深拷贝在开发过程中主要用于防止副作用、处理复杂嵌套结构、避免多线程环境中的数据竞争以及实现历史记录和撤销功能。根据具体需求和场景选择使用深拷贝可以提高代码的健壮性和可维护性。
(4)举例:例如以上的列表list1中,有[1, 2]、(30, 40)、'kkk'三个元素,首先列表本身list1是可变的类型,元素[1, 2]是可变的,元素(30, 40)和'kkk'是不可变的。(1)对象:对象有存储地址id【就好像某个地址的快递仓库】,对象中的元素都有一个地址id【就像仓库的某某货架】(2)对象与对象的元素:(对象)或(对象中的元素)有不同的类型【数字,字符串,列表,字典,集合,元组】定义:可变就是增删改查之后,对象或元素的存储id不会发生改变,反之就不可变。
由于新对象与原始对象并无共享内存地址,故而二者完全独立,因此更改其中一个对象的值并不会影响另一个对象的值。浅复制是指新建一个对象,然后将原始对象的引用复制给新对象。由于新对象与原始对象同一内存地址,因此一个对象的值被修改后,另一个对象的值也会受到影响。深拷贝和浅拷贝在Python中是非常重要的存在,但很多人对它们了解的并不是很清楚,本文为大家详细讲解一下深浅拷贝的概念、使用场景以及注意事项,希望能够给你带来帮助。在使用深拷贝时,如果对象的层次结构比较复杂,可能会导致性能问题,因此必须小心使用深拷贝。
常规拷贝在原始变量 x 的改变后,因为共用同一个内存地址,因此会直接放到被复制的变量 y 上,导致“不知情”的情况下导致 y 变量在没有操作的情况下改变。
解决办法就是使用浅拷贝
浅拷贝会将两个变量分别放在不同的内存地址,解决了常规拷贝的缺点。
但是,对于字典或列表中有嵌套的情况,浅拷贝同样不会生效。
这时候就需要用的深拷贝。
可以看到,深拷贝可以解决
除ID之外,其他状态都有可能发生改变可变对象有:列表、集合、字典l = []print("修改前id= ", id(l))print("修改后id= ", id(l))print(l)结果:修改前id= 2597667097216修改后id= 2597667097216[132]2、什么是不可变对象,有哪些?包括id在内的各种状态,都不会发生变化不可变对象有:大部分是python内置数据类型: 数字,字符串,元组i = 123print("修改前id= ", id(i))
copy函数是浅拷贝,只对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间进行存储,不会拷贝对象内部的子对象。对于不可变对象而言,浅拷贝只是引用赋值。deepcopy函数是深拷贝,对于可变类型,深拷贝是逐层进行拷贝。对于不可变类型而言,也是引用赋值。# 对于不可变对象来说,无论深浅拷贝 都不会进行拷贝,只是引用赋值。# 对于可变对象,浅拷贝只拷贝第一层数据,深拷贝会逐层拷贝。可变对象中,保存的可变数据。可变对象中保存不可变数据。