知行编程网知行编程网  2022-01-18 15:47 知行编程网 隐藏边栏 |   抢沙发  2 
文章评分 0 次,平均分 0.0

在讲深浅拷贝之前,我们先重温一下 is==的区别。

在判断对象是否相等比较的时候我们可以用is==

  • is:比较两个对象的引用是否相同,即 它们的id 是否一样

  • == :比较两个对象的值是否相同。

id() ,是Python的一个内置函数,返回对象的唯一标识,用于获取对象的内存地址。

如下

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

首先,会为整数1分配一个内存空间。变量a 和 b 都指向了这个内存空间(内存地址相等),所以他们的id相等。
a is bTrue
但是,真的所有整数数字都这样吗?
答案是:不是!
只有在 -25 ~ 256范围中的整数才不会重新分配内存空间。
如下所示:
因为257 超出了范围,所以id不相同,所以a is b返回的值为False。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

这样做是考虑到性能,Python对-5 到 256 的整数维护了一个数组,相当于一个缓存, 当数值在这个范围内,直接就从数组中返回相对应的引用地址了。如果不在这个范围内,会重新开辟一个新的内存空间。

is 和 == 哪个效率高?

相比之下,is比较的效率更高,因为它只需要判断两个对象的id是否相同即可。
== 则需要重载eq 这个函数,遍历变量中的所有元素内容,逐次比较是否相同。因此效率较低

浅拷贝 深拷贝

给变量进行赋值有两种方法:直接赋值,拷贝
直接赋值就 = 就可以了。而拷贝又分为浅拷贝和深拷贝
先说结论吧:
  • 浅拷贝:拷贝的是对象的引用,如果原对象改变,相应的拷贝对象也会发生改变
  • 深拷贝:拷贝对象中的每个元素,拷贝对象和原有对象不在有关系,两个是独立的对象
光看上面的概念,对新手来讲可能不太好理解。来看下面的例子吧
 

赋值

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

定义变量a,同时将a赋值给b。打印之后发现他们的id是相同的。说明指向了同一个内存地址。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

然后修改a的值,再查看他们的id

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

这时候发现修改后的a和b以及最开始的a的内存地址是一样的。也就是说a和b还是指向了那一块内存,只不过内存里面的[1, 2, 3] 变成了[1, 0, 3]
因为每次重新执行的时候内存地址都是发生改变的,此时的id(a) 的值46169960与52531048是一样的
所以我们就可以判断出,b和a的引用是相同的,当a发生改变的时候,b也会发生改变。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

赋值就是:你a无论怎么变,你指向谁,我b就跟着你指向谁。

拷贝

提到拷贝就避免不了可变对象和不可变对象。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

  • 可变对象:当有需要改变对象内部的值的时候,这个对象的id不发生变化。
  • 不可变对象:当有需要改变对象内部的值的时候,这个对象的id会发生变化。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

浅拷贝

拷贝的是不可变对象,一定程度上来讲等同于赋值操作。但是对于多层嵌套结构,浅拷贝只拷贝父对象,不拷贝内部的子对象。
使用copy模块的 copy.copy 进行浅拷贝。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

通俗的讲,我将现在的a 复制一份重新分配了一个内存空间。后面你a无论怎么改变,那跟我b是没有任何关系的。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

对于列表的浅拷贝还可以通过list(), list[:] 来实现
但是!我前面提到了对于多层嵌套的结构,需要注意
看下面的例子

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

b是由a浅拷贝得到的。我修改了a中嵌套的列表,发现b也跟着修改了?
如果还是不太理解,可以参考下图。LIST就是一个嵌套的子对象,指向了另外一个内存空间。所以浅拷贝只是拷贝了元素12 和子对象的引用!
就好比我在公司订了外卖,告诉了送餐员我的地址是 “朝阳区 xx科技园 B栋3楼。但是我突然被通知4楼过需求了,送餐员收到的地址是3楼,至于3楼谁吃这个饭他并不知道。送餐员只需要将餐成功的送到(指向)3楼(List)即可!

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

另外一种情况,如果嵌套的是一个元组呢?

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

我们发现浅拷贝得来的b并没有发生改变。因为元组是不可变对象。改变了元组就会生成新的对象。b中的元组引用还是指向了旧的元组。

深拷贝

所谓深拷贝呢,就是重新分配一个内存空间(新对象),将原对象中的所有元素通过递归的方式进行拷贝到新对象中。
在Python中 通过copy.deepcopy()来实现深拷贝。

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

天啦噜!仅仅5张图,彻底搞懂Python中的深浅拷贝

 

结语

1、深浅拷贝都会对源对象进行复制,占用不同的内存空间

2、如果源对象没有子目录,则浅拷贝只能拷贝父目录,改动子目录时会影响浅拷贝的对象

3、列表的切片本质就是浅拷贝

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

知行编程网
知行编程网 关注:1    粉丝:1
这个人很懒,什么都没写

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享