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

通俗易懂,搞定Python中的深拷贝和浅拷贝

时间:2023-03-26 13:55:18 Python

Python中的深拷贝和浅拷贝在说深拷贝和浅拷贝之前,我想先说一下is和==的区别。在比较对象是否相等时,我们可以使用is和==is:比较两个对象的引用是否相同,即id是否相同==:比较两个对象的值是否相同相同。id()是Python的内置函数,返回对象的唯一标识,用于获取对象的内存地址。如下a=1b=1print(id(a))#2057422768print(id(b))#2057422768print(aisb)#True首先会为整数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__函数,遍历变量中所有元素的内容,逐一比较是否相同。所以浅拷贝和深拷贝的效率都比较低。了解完is和==,我们再来看看Python中的深拷贝和浅拷贝。先说结论:浅拷贝:拷贝的是对象的引用。如果原始对象发生变化,则相应的复制对象也会发生变化。深拷贝:复制对象中的每一个元素,复制对象与原对象不再相关。一个是独立对象浅拷贝a=[1,2,3]b=list(a)#可以通过list对list进行浅拷贝c=a.copy()#也可以通过copy进行拷贝function#浅拷贝后,a/b/c的id不同,表示指向不同的内存地址——即生成了一个新对象print(id(a))#16301992print(b,"id:",id(b))#id:16562024print(c,"id:",id(c))#id:16561960print(a==b)#真值相同returnTrueprint(aisb)#假id不同所以比较返回False#给列表添加一个元素4a.append(4)print(a)#[1,2,3,4]print(b,c)#[1,2,3][1,2,3]b和c不受上面的影响可见浅拷贝会分配新的内存空间,创建新的对象。但是如果复制的对象中有可变对象怎么办?看下面代码a=[1,2,[3,4]]b=a.copy()print(id(a))#23967528print(id(b))#21738984#改变a中的变量对象a[-1].append(5)print(a)#向a添加新元素6a.append(6)#[1,2,[3,4,5],6]print(a)#[1,2,[3,4,5]]print(b)可以看出lista中新加入的元素6并没有影响b。但是a的嵌套列表中的新元素5会影响元素b。原因是:a和b都指向同一个列表[3,4]。所以当a中的链表加入一个元素5时,那个链表的值就变了,b也指向那个链表,所以它也会变。看下面的代码a=[1,2,(3,4)]b=a.copy()print(id(a))#59162536print(id(b))#60143400#改变一个对象a中的变量[-1]+=(5,)#[1,2,(3,4,5)]print(a)#[1,2,(3,4)]print(b)对于元组(3,4),因为元组是不可变的,所以在元组中增加了一个新的元素5,实际上生成了一个新的元组对象。b列表中的元组引用没有改变。通过上面两个例子,我们可以看出浅拷贝可能带来的弊端,大家在使用中需要做出相应的判断。或者说完全复制一个对象,也就是深拷贝。深拷贝所谓深拷贝就是重新分配一块内存空间(新对象),将原对象中的所有元素递归复制到新对象中。在Python中,深拷贝是通过copy.deepcopy()实现的。importcopya=[1,2,(3,4)]#深拷贝b=copy.deepcopy(a)#因为生成了一个新的对象,returnFalseprint(aisb)a[-1]+=(5,)a.append(6)print(a)#[1,2,(3,4,5),6]print(b)#[1,2,(3,4)]深拷贝后的对象,就是完全不受原始对象的影响……福利在文末,史上最全的Python资料合集(长期更新)。隔壁的孩子都哭了---点击收藏