背景介绍
在了解python中深拷贝和浅拷贝之前,我们还是要花一点时间来了解一下python内存中变量的存储情况。对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的值本身。最简单的如下图所示:
Python中的对不同类型的数据深浅拷贝也不同,主要分两种,一种是数字和字符串,另一种就是列表、元组、字典等其他类型,下面通过字符串和列表的例子来介绍一下有什么不同。
赋值
对象的赋值其实就是对象的引用。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。
下面一段代码我们想实现给字符串和列表中的字符串分别加个后缀,通过这个来看看对不同类型的数据的赋值的区别以及存在的问题,代码如下所示:
结果:
从上图可以看出,对于赋值操作,绿色框的横向对比,两种类型的数据进行赋值后地址没有变化,都是对同一地址的引用;但是红色框的纵向对比发现字符串加后缀后地址发生变化,每次循环加的后缀也不同,但是列表中的字符串重复添加,地址也没有变化。
这是因为对于同一个字符串,python并不会开辟一块新的内存空间,而是维护同一块内存地址;而对于列表,赋值只是对同一对象的引用,存储地址不变化。如果希望列表中字符串也发生变化,可以使用浅拷贝来实现。
浅拷贝
浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制,也就是只拷贝第一层地址。将赋值修改为浅拷贝后,如下图所示:
结果:
从上图可以看出,对于浅拷贝操作,绿色框的横向对比,字符串的赋值后地址没有变化,但是列表的发生了变化;通过红色框的纵向对比发现字符串和k1的后缀发送了变化,但是库k3中的字符串出现了和之前k1相同的问题。如果想改变上述情况,希望列表中库k3字符串也发生变化,可以使用深拷贝来实现。
深拷贝
深拷贝:外围和内部元素都进行了拷贝对象本身,而不是引用。也就是,把对象复制一遍,并且该对象中引用的其他对象我也复制。不管嵌套多少层,都会拷贝多少层出来,但是最底层的数字和字符串地址不变。
结果:
从上图可以看出,对于深拷贝操作,绿色框的横向对比,字符串的赋值后地址没有变化,但是列表的发生了变化,但是红色框的纵向对比发现字符串和k1、k3的后缀都发送了变化。
总结
对于不可变类型的对象,赋值、深浅拷贝最终的地址值和值都是相等的,如果修改对象后,会自动分配新的空间。对于可变类型,赋值不改变地址,是对原对象的引用;而深浅拷贝都是对源对象的复制,会占用不同的内存空间,复制的层次略有区别。欢迎大家批评指正~
Qtest是360旗下的专业测试团队!
是WEB平台部测试技术平台化、效率化的先锋力量!
领取专属 10元无门槛券
私享最新 技术干货