当前位置: 首页 > 后端技术 > Python

python中的浅拷贝和深拷贝

时间:2023-03-26 00:30:02 Python

分为浅拷贝和深拷贝shallowcopy重新分配一块内存,创建一个新的对象,里面的元素是对被拷贝对象的子元素的引用。-特点:将创建一个新对象。这个对象不是对原对象的引用,而是对原对象中一级子元素对象的引用。importcopy#L1对象内部有两个元素:index0:[1,2],index1:(100,200)L1=[[1,2],(100,200)]#做一个L1的浅拷贝,此时,获取一个新的List对象赋值给L2,L2=list(L1)print("L1的内存地址为--{},第一个元素的地址--{},第一个元素的地址第二个元素--{}".format(id(L1),id(L1[0]),id(L1[1])))print("L2的内存地址为--{},第一个元素--{},第二个元素的地址--{}".format(id(L2),id(L2[0]),id(L2[1])))#L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568#L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址element--2581951586568#修改common为引用列表的内容,由于L1和L2的第一个元素指向这个列表,因此L1和L2对应的元素的内容发生变化d,但id不变。L1[0].append(3)print(L1)#[[1,2,3],(100,200)]print(L2)#[[1,2,3],(100,200)]#L1中添加的元素,L1和L2相互独立,不会受到影响L1.append(100)print(L1)#[[1,2,3],(100,200),100]print(L2)#[[1,2,3],(100,200)]#元组是不可变的,因此,元组使用+得到一个新的元组对象,所以L2中的元组对象id不变,而L1中的元组对象身份证已经改变。L1[1]+=(500,600)print(L1)#[[1,2,3],(100,200,500,600),100]print(L2)#[[1,2,3],(100,200)]print("L1的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1),id(L1[0]),id(L1[1])))print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2),id(L2[0]),id(L2[1])))#L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581952542584#L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568#列表是可变的,+号操作是在前面的基础上添加新元素,类似list的extend方法L1[0]+=[3000,4000]print(L1)#[[1,2,3,3000,4000],(100,200,500,600),100]print(L2)#[[1,2,3,3000,4000],(100,200)]print("内存地址L1的s是--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L1),id(L1[0]),id(L1[1])))print("L2的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L2),id(L2[0]),id(L2[1])))#L1的内存地址为--2581953960968,第一个元素的地址--2581953961032,第二个元素的地址--2581952542584#L2的内存地址为--2581953936904,第一个元素的地址--2581953961032,第二个元素的地址--2581951586568实现方法:该对象类型的工厂函数,切片操作(对某些类型的对象有效)复制复制模块中的函数L1=[[100,200],(1000,2000)]L3=list(L1)L4=L1[:]L5=copy.copy(L1)print("L3的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L3),id(L3[0]),id(L3[1])))print("L4的内存地址是--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L4),id(L4[0]),id(L4[1])))print("L5的内存地址为--{},第一个元素的地址--{},第二个元素的地址--{}".format(id(L5),id(L5[0]),id(L5[1])))#L3的内存地址为--2581952584392,第一个元素的地址--2581953960904,第二个元素的地址--2581951626888#L4的内存地址为--2581953960968,第一个元素的地址--2581953960904,第二个元素的地址--2581951626888#L5的内存地址为--2581953936968,第一个元素的地址--2581953960904,第二个的地址element--2581951626888组,浅拷贝不创建吃新内存,但使新变量指向复制对象的内存地址s1=(100,200)s2=tuple(s1)s3=s1[:]s4=copy.copy(s1)print(id(s1))#2399341093128print(id(s2))#2399341093128print(id(s3))#2399341093128print(id(s4))#2399341093128deepcopy深拷贝重新分配一块内存,新建一个对象,复制对象中的所有元素递归复制到这个新对象。新对象与原对象完全独立,互不影响。importcopyL1=[[1,2],(100,200)]L2=copy.deepcopy(L1)print("L1的内存地址为--{},第一个元素的地址--{},第二个元素--{}的地址".format(id(L1),id(L1[0]),id(L1[1])))print("L2的内存地址为--{},第一个元素address--{},第二个元素的地址--{}".format(id(L2),id(L2[0]),id(L2[1])))#L1的内存地址为--1665896340552,第一个元素的地址--1665896340616,第二个元素的地址--1665893966024#L2的内存地址为--1665896340488,第一个元素的地址--1665896340808,第二个元素的地址--1665893966024L1[0].append(3)print(L1)#[[1,2,3],(100,200)]print(L2)#[[1,2],(100,200)]L1。append(1000)print(L1)#[[1,2,3],(100,200),1000]print(L2)#[[1,2],(100,200)]-注意:这里,L1和L2中元组的内存地址是一样的,但是不影响,因为元组是不可变对象,不能被其他操作改变。可以共享。-特例:l1=[[1,2],(30,40)]l2=copy.deepcopy(l1)l1.append(100)l1[0].append(3)print(l1)#[[1,2,3],(30,40),100]print(l2)#[[1,2],(30,40)]在这个例子中,列表x中有对自身的引用,所以x是无限嵌入列表集。但是将x深拷贝到y之后,程序并没有出现栈溢出的现象。这是因为深拷贝函数deepcopy会维护一个字典来记录被拷贝的对象及其ID。在复制过程中,如果要复制的对象已经存在字典中,则直接从字典中返回。defdeepcopy(x,memo=None,_nil=[]):"""对任意Python对象的深度复制操作。有关更多信息,请参阅模块的__doc__字符串。"""如果memo为None:memo={}d=id(x)#查询被复制对象的idxy=memo.get(d,_nil)#查询对象是否已经存储在字典中ifyisnot_nil:returny#如果要复制的对象已经存储在字典中,然后直接返回