Python中的深拷贝和浅拷贝在说深拷贝和浅拷贝之前,我们先回顾一下is和==的区别。在判断对象是否相等的时候,我们可以使用is和==is:比较两个对象的引用是否相同,即它们的id是否相同==:比较的值是否相同两个对象相同。id()是Python的内置函数,返回对象的唯一标识,用于获取对象的内存地址。如下首先,会为整数1分配一块内存空间,变量a和b都指向这块内存空间(内存地址相等),所以它们的ids相等。即aisbisTrue但是所有整数都是这样吗?答案是不!只有-25~256范围内的整数不会重新分配内存空间。如下:因为257超出范围,id不一样,所以a为b返回的值为False。>>>a=257>>>b=257>>>print(id(a))20004752>>>print(id(b))20001312>>>print(aisb)False>>>print(a==b)True这样做是出于对性能的考虑。Python维护了一个-5到256的整数数组,相当于一个缓存。当值在这个范围内时,直接从数组中返回对应的引用地址。如果不在这个范围内,就会重新开辟一个新的内存空间。哪个更有效,是or==?相比之下,is比较效率更高,因为它只需要判断两个对象的id是否相同。而==需要重载__eq__函数,遍历变量中所有元素的内容,逐一比较是否相同。因此,浅拷贝和深拷贝给变量赋值的效率较低。有两种方法:直接赋值,copy和直接赋值=即可。而拷贝又分为浅拷贝和深拷贝。先说结论:浅拷贝:拷贝的是对象的引用。如果原始对象发生变化,则相应的复制对象也会发生变化。深拷贝:复制对象中的每一个元素,复制的对象与原对象没有任何关系。两者是独立的对象。单看上面的概念,新手可能不太容易理解。我们看下面的例子赋值a=[1,2,3]b=aprint(id(a))#52531048print(id(b))#52531048定义变量a,同时将a赋值给b。打印出来后发现他们的id是一样的。描述指向相同的内存地址。然后修改a的值,查看他们的ida=[1,2,3]b=aprint(id(a))#46169960a[1]=0print(a,b)#[1,0,3][1,0,3]print(id(a))#46169960print(id(b))#46169960这时候发现修改后的a和b的内存地址和原来的a是一样的。也就是说a和b还是指向那块内存,但是内存中的[1,2,3]变成了[1,0,3],因为每次重新执行时内存地址都变了。此时id(a)46169960的值和52531048是一样的,所以我们可以判断b和a的引用是一样的,当a改变时,b也会改变。赋值是:不管你a怎么变,你指向谁,我b就跟着你指向谁。复制谈到复制,可变对象和不可变对象是不可避免的。可变对象:当对象内部的值需要改变时,对象的id不会改变。不可变对象:当对象内部的值需要改变时,对象的id也会改变。a=[1,2,3]print(id(a))#56082504a.append(4)#修改列表a后,id没有变,变量对象print(id(a))#56082504a='hello'print(id(a))#59817760a=a+'world'print(id(a))#57880072#修改字符串a后,id变了。Immutableobjectprint(a)#helloworld的浅拷贝复制了一个不可变对象,在一定程度上相当于一个赋值操作。但是对于多层嵌套结构,浅拷贝只复制父对象,不复制内部子对象。使用copy模块中的copy.copy进行浅拷贝。importcopya=[1,2,3]b=copy.copy(a)print(id(a))#55755880print(id(b))#55737992a[1]=0print(a,b)#[1,0,3][1,2,3]一般来说,我复制了当前的a,重新分配了一块内存空间。你以后怎么改a跟b没关系。列表的浅拷贝也可以通过list()实现,list[:]但是!前面提到对于多层嵌套结构,需要注意下面的例子importcopya=[1,2,[3,4]]b=copy.copy(a)print(id(a))#23967528print(id(b))#21738984#改变a[-1].append(5)print(a)#[1,2,[3,4,5]]print(b)#[1,2,[3,4,5]]??为什么不是[1,2,[3,4]]?b是通过浅拷贝获得的。我修改了a中的嵌套列表,发现b也被修改了?如果还是不明白,可以参考下图。LIST是一个嵌套的子对象,指向另一个内存空间。所以浅拷贝只是复制元素1、2和对子对象的引用!另一种情况,如果嵌套是元组怎么办?importcopya=[1,2,(3,4)]b=copy.copy(a)#改变a中的元组a[-1]+=(5,)print(a)#[1,2,(3,4,5)]print(b)#[1,2,(3,4)]我们发现浅拷贝得到的b没有变化。因为元组是不可变的对象。更改元组会创建一个新对象。b中的元组引用仍然指向旧元组。深拷贝所谓深拷贝就是重新分配一块内存空间(新对象),将原对象中的所有元素递归复制到新对象中。在Python中,深拷贝是通过copy.deepcopy()实现的。importcopya=[1,2,[3,4]]b=copy.deepcopy(a)print(id(a))#66587176print(id(b))#66587688#改变a[-1中的变量对象a.append(5)print(a)#[1,2,[3,4,5]]print(b)#[1,2,[3,4]]深拷贝后,单词列表不会受原结论1的影响,深拷贝和浅拷贝都会拷贝源对象,占用不同的内存空间。2.如果源对象没有子目录,浅拷贝只能复制父目录。当子目录改变时,浅拷贝对象会受到影响。3.List切片的本质是浅拷贝史上最全的Python数据集合(长期更新)。隔壁的孩子都哭了---点击收藏
