前些天做了个小程序,遇到了Python的深浅拷贝问题
感觉自己基础不够扎实,就翻了翻教程,真的是非常基础的知识。。。(各位大佬下手轻点2333)
下面简单说说:
首先有个字典a
1 a = {‘A‘:1,‘B‘:2,‘C‘:3,‘D‘:4}
然后我们把它赋值给另外一个空字典b
1 b = {} 2 b = a
当我们输出b时,可以看到a和b直观上看好像是相等了
按照常理,我们会认为a和b现在是两个值相等的字典,如果我们对其中一个操作,另外一个应该不会受到影响才对,所以我们试一下:
我们尝试删除b中的一个键值对
1 b.pop(‘A‘)
输出b
理所当然地b其中一个键值对被删除了
然后我们试着输出a,诡异的事情发生了
我们只是对b进行了键值对的删除,怎么a的值也变了?
原因就是Python的赋值原理
其实我们所谓的将a赋值给了b,赋给b的并不是a的值,而是a所存储的值的地址
所以当我们输出b的时候,输出的是和a一样的值
因此,我们对b进行的操作,都会影响到在内存中的{‘A‘:1,‘B‘:2,‘C‘:3,‘D‘:4}
当我们删除b的一个键值对时,其实就是对{‘A‘:1,‘B‘:2,‘C‘:3,‘D‘:4}的键值对进行了删除
此时a和b指向的就是新的字典{‘B‘: 2, ‘C‘: 3, ‘D‘: 4}
所以我们输出的时候发现值的变更
那么,如何真正的拷贝值呢?
这里就涉及到Python的深浅拷贝问题
使用Python的copy()和deepcopy()方法可以实现浅拷贝和深拷贝
什么是浅拷贝和深拷贝?
浅拷贝只对对象中的父对象进行拷贝,但不会连同其子对象一同复制
深拷贝则是对对象中的所有对象包括其子对象进行复制
举个例子:
(因为copy()方法和deepcopy()方法需要调用copy模块,故我们先提前引用)
import copy
定义字典a
1 a = {‘A‘:1,‘B‘:2,‘C‘:3,‘D‘:[1,2,3]}
作为对照组,我们创建b,同样将a赋给它(其实是传,你应该知道为什么了)
b = a
现在我们先进行浅拷贝
创建c,接收a的浅拷贝
1 c = copy.copy(a)
接下来进行深拷贝
1 d = copy.deepcopy(a)
之后,我们对a进行一系列改动,观察b,c,d的值的变化
首先我们对a的某键值对进行删除
1 a.pop(‘A‘)
然后我们对a中键为D的子对象进行改动,我们在D中添加一个子对象
a[‘D‘].append(4)
现在,我们分别输出a,b,c,d,观察他们的区别
首先是a,很显然的结果
其次是b,因为赋给引用的原因,同样会被改变,与a的值相同
再输出c,发现了端倪
再看看d
我们发现,a和b中的父对象及其子对象均受到了改变
c虽然父对象没有受到影响,但是其中键值为D的元素值(列表)发生了改变,所以由此我们发现,浅拷贝只会复制对象中的父对象,而其子对象在源数据收到改变时,仍会收到相同的影响
再转过来看d,与被我们改动前的a完全相同,所以说深拷贝非常完整地实现了对象的复制,由此我们发现,深拷贝可以复制对象的全部内容包括其子对象
为了更直观一点,可以参考下面的图:
所以,在进行数据拷贝时,可以视情况考虑拷贝的方式。当然这里还涉及到数据类型的可变和不可变类型的因素,这里不做过多讨论。
本文部分内容参考了Alex大佬的博客,对Python的深浅拷贝进行了非常详细的讨论,十分推荐大家去学习
传送门https://m.2cto.com/net/201606/515654.html
原文地址:https://www.cnblogs.com/seikito/p/9448142.html