Python中的深复制浅复制(等号赋值、copy和deepcopy的区别)

(作者:陈玓玏)

不是那么有耐心的朋友可以直接看总结!

一、深复制浅复制的区别

以我比较愚笨的理解,浅复制就是,仅复制对象的引用,而不新开辟内存,也就是说,会共享指针,当你改变复制后的对象时,其实是在改变原对象内存中的内容。

而深复制的意思是,会将新开辟内存,并把原对象内存中的内容复制到新的内存中来,如果你改变复制后的对象,是不会改变原对象的内容的,这就是说两个对象在完成复制之后,已经是两个独立的对象了。

Python中的深复制和浅复制可以通过copy包中的copy函数和deepcopy函数来实现,实际上,对于三类可变对象list、dict和set而言,还可以通过对象的copy方法来实现浅复制。另外,对于所有对象而言,直接赋值就是浅复制。

二、改变复制后对象对原对象的影响

看例子:
下面的例子都只包含可变对象,因为不可变对象的这些内容没什么好研究的,它们的深复制浅复制内容并不会有什么不一样,因为它们是不可变对象,一经生成,要改变它们的值就一定会新开辟内存,重新生成一个新的对象。所以,只有下面的可变对象有研究价值。

#调用的包
from copy import copy,deepcopy

#用到的基础数据
strA = 'hhhhheeeee'
intA = 1
tupleA = (0,1,2)
listA = [0,1,2]
dictA = {'a':0,'b':1,'c':2}
setA = {0,1,2}
listList = [[0,1,2],[0,1,2]]

#通过赋值的方法来改变list对象,这样新的listB其实和原来的listB已经不是同一个内存了
#,所以虽然是浅复制,但是通过赋值来改变对象值的方法,对原对象没有影响
listB = copy(listA)
listB = listB+[3]
print(listB,listA)
结果:
[0, 1, 2, 3] [0, 1, 2]

#同上,虽然是通过赋值实现浅复制,但listB已经是一个新的对象了
listB = listA
listB = listB+[3]
print(listB,listA)
结果:
[0, 1, 2, 3] [0, 1, 2]

#浅复制,但是通过append改变值,没有返回新的对象,而是直接改变原来的listB,listA的值也随之改变
listB = listA
listB.append(3)
print(listB,listA)
结果:
[0, 1, 2, 3] [0, 1, 2, 3]

#简单对象的copy和deepcopy无区别,外层对象的改变不同步
listB = listA.copy()
listB.append(3)
print(listB,listA)
结果:
[0, 1, 2, 3, 3] [0, 1, 2, 3]

#深复制,但是由于对象是简单数据结构,所以效果与copy一样
listB = deepcopy(listA)
listB.append(3)
print(listB,listA)
结果:
[0, 1, 2, 3, 3] [0, 1, 2, 3]

#复杂数据结构的浅复制,改变外层对象,原对象不随之改变
listL = listList.copy()
listL.append(3)
print(listL,listList)
#结果:
[[0, 1, 2], [0, 1, 2], 3] [[0, 1, 2], [0, 1, 2]]

#复杂数据结构的浅复制,只拷贝了外层对象,但内层对象还是共享的,因此改变内层对象会同步改变原对象的内层对象
listL = listList.copy()
listL[0].append(3)
print(listL,listList)
结果:
[[0, 1, 2, 3], [0, 1, 2]] [[0, 1, 2, 3], [0, 1, 2]]

#复杂数据结构的深复制,内外层对象都拷贝过来了,因此改变新对象的内层对象也不会改变原对象
listL = deepcopy(listList)
listL[0].append(3)
print(listL,listList)
结果:
[[0, 1, 2, 3, 3], [0, 1, 2]] [[0, 1, 2, 3], [0, 1, 2]]

三、总结

总结一下就是:

1、只有可变对象存在深复制和浅复制的区别,不可变对象无异;

2、直接赋值复制、copy复制和deepcopy复制都不同。
1) 对于简单对象,只有直接赋值的新对象改变会影响原对象,copy和deepcopy都不会;
2)而对于复杂对象,也就是有嵌套的数据结构,改变外层对象时,只有直接赋值会改变原对象;
3)而改变内层对象时,直接赋值和copy都将改变原对象;

3、如果改变新对象是通过赋值的方法改变的,即使共享变量名,也是开辟新内存,无论赋值方式都不改变原对象,而通过appned等内置方法改变新对象的,原对象视赋值方法及改变内容的层级,相应改变。

结论:
我们可以把复制理解为三个层次,第一层是赋值,赋值后两个引用指向的是同一个对象。第二层是浅复制,浅复制会复制对象的属性(引用属性和数值属性),但是不会把引用属性指向的对象。第三层为深复制,会复制一切属性和属性指向的对象内存。

猜你喜欢

转载自blog.csdn.net/weixin_39750084/article/details/81435454
今日推荐