python中copy()与deepcopy()的区别小结


Posted in Python onAugust 03, 2018

前言

copy()与deepcopy()之间的区分必须要涉及到python对于数据的存储方式。

深复制被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。

浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。

import copy
 origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
cop1 = copy.copy(origin)
cop2 = copy.deepcopy(origin)
cop1 == cop2
------>True
 cop1 is cop2
------>False 
#cop1 和 cop2 看上去相同,但已不再是同一个object
 origin[2][0] = "hey!" 
 origin
------>[1, 2, ['hey!', 4]]
 cop1
------>[1, 2, ['hey!', 4]]
 cop2
------>[1, 2, [3, 4]]

可以看到 cop1,也就是 copy 跟着 origin 改变了。而 cop2 ,也就是 deep copy 并没有变。

Python存储方式

Python 存储变量的方法跟其他 OOP 语言不同。它与其说是把值赋给变量,不如说是给变量建立了一个到具体值的 reference。

当在 Python 中 a = something 应该理解为给 something 贴上了一个标签 a。当再赋值给 a 的时候,就好象把 a 这个标签从原来的 something 上拿下来,贴到其他对象上,建立新的 reference。 这就解释了一些 Python 中可能遇到的诡异情况:

>> a = [1, 2, 3]
>>> b = a
>>> a = [4, 5, 6] //赋新的值给 a
>>> a
[4, 5, 6]
>>> b
[1, 2, 3]
# a 的值改变后,b 并没有随着 a 变

>>> a = [1, 2, 3]
>>> b = a
>>> a[0], a[1], a[2] = 4, 5, 6 //改变原来 list 中的元素
>>> a
[4, 5, 6]
>>> b
[4, 5, 6]
# a 的值改变后,b 随着 a 变了

上面两段代码中,a 的值都发生了变化。区别在于,第一段代码中是直接赋给了 a 新的值(从 [1, 2, 3] 变为 [4, 5, 6]);而第二段则是把 list 中每个元素分别改变。

而对 b 的影响则是不同的,一个没有让 b 的值发生改变,另一个变了。怎么用上边的道理来解释这个诡异的不同呢?

首次把 [1, 2, 3] 看成一个物品。a = [1, 2, 3] 就相当于给这个物品上贴上 a 这个标签。而 b = a 就是给这个物品又贴上了一个 b 的标签。

python中copy()与deepcopy()的区别小结

第一种情况:

a = [4, 5, 6] 就相当于把 a 标签从 [1 ,2, 3] 上撕下来,贴到了 [4, 5, 6] 上。

在这个过程中,[1, 2, 3] 这个物品并没有消失。 b 自始至终都好好的贴在 [1, 2, 3] 上,既然这个 reference 也没有改变过。 b 的值自然不变。

python中copy()与deepcopy()的区别小结

第二种情况:

a[0], a[1], a[2] = 4, 5, 6 则是直接改变了 [1, 2, 3] 这个物品本身。把它内部的每一部分都重新改装了一下。内部改装完毕后,[1, 2, 3] 本身变成了 [4, 5, 6]。

而在此过程当中,a 和 b 都没有动,他们还贴在那个物品上。因此自然 a b 的值都变成了 [4, 5, 6]。

搞明白这个之后就要问了,对于一个复杂对象的浅copy,在copy的时候到底发生了什么?
再看一段代码:

>>> import copy
>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)
>>> cop1 == cop2
True
>>> cop1 is cop2
False 
#cop1 和 cop2 看上去相同,但已不再是同一个object
>>> origin[2][0] = "hey!" 
>>> origin
[1, 2, ['hey!', 4]]
>>> cop1
[1, 2, ['hey!', 4]]
>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2

学过docker的人应该对镜像这个概念不陌生,我们可以把镜像的概念套用在copy上面。

概念图如下:

python中copy()与deepcopy()的区别小结

copy对于一个复杂对象的子对象并不会完全复制,什么是复杂对象的子对象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是复杂对象的子对象。对于子对象,python会把它当作一个公共镜像存储起来,所有对他的复制都被当成一个引用,所以说当其中一个引用将镜像改变了之后另一个引用使用镜像的时候镜像已经被改变了。

所以说看这里的origin[2],也就是 [3, 4] 这个 list。根据 shallow copy 的定义,在 cop1[2] 指向的是同一个 list [3, 4]。那么,如果这里我们改变了这个 list,就会导致 origin 和 cop1 同时改变。这就是为什么上边 origin[2][0] = “hey!” 之后,cop1 也随之变成了 [1, 2, [‘hey!', 4]]。

而deepcopy概念图如下:

python中copy()与deepcopy()的区别小结

deepcopy的时候会将复杂对象的每一层复制一个单独的个体出来。

这时候的 origin[2] 和 cop2[2] 虽然值都等于 [3, 4],但已经不是同一个 list了。即我们寻常意义上的复制。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python发腾讯微博代码分享
Jan 10 Python
python实现批量修改图片格式和尺寸
Jun 07 Python
使用Python的Dataframe取两列时间值相差一年的所有行方法
Jul 10 Python
python安装twisted的问题解析
Aug 21 Python
Python unittest 简单实现参数化的方法
Nov 30 Python
python按照多个条件排序的方法
Feb 08 Python
python pandas 时间日期的处理实现
Jul 30 Python
python实现kNN算法识别手写体数字的示例代码
Aug 16 Python
pandas 空数据处理方法详解
Nov 02 Python
python3实现raspberry pi(树莓派)4驱小车控制程序
Feb 12 Python
使用Python第三方库pygame写个贪吃蛇小游戏
Mar 06 Python
selenium.webdriver中add_argument方法常用参数表
Apr 08 Python
Python爬取个人微信朋友信息操作示例
Aug 03 #Python
python opencv人脸检测提取及保存方法
Aug 03 #Python
Python爬虫爬取新浪微博内容示例【基于代理IP】
Aug 03 #Python
OpenCV+python手势识别框架和实例讲解
Aug 03 #Python
Windows下将Python文件打包成.EXE可执行文件的方法
Aug 03 #Python
Python测试网络连通性示例【基于ping】
Aug 03 #Python
python版opencv摄像头人脸实时检测方法
Aug 03 #Python
You might like
DC漫画《蝙蝠侠和猫女》图透 猫女怀孕老爷当爹
2020/04/09 欧美动漫
有关 PHP 和 MySQL 时区的一点总结
2008/03/26 PHP
php定时计划任务的实现方法详解
2013/06/06 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十六)
2014/06/30 PHP
IE浏览器IFrame对象内存不释放问题解决方法
2014/08/22 Javascript
js实现网页随机切换背景图片的方法
2014/11/01 Javascript
jQuery选择器源码解读(五):tokenize的解析过程
2015/03/31 Javascript
angularjs在ng-repeat中使用ng-model遇到的问题
2016/01/21 Javascript
js接收并转化Java中的数组对象的方法
2016/08/11 Javascript
详解js运算符单竖杠“|”与“||”的用法和作用介绍
2016/11/04 Javascript
NodeJs的fs读写删除移动监听
2017/04/28 NodeJs
jQuery Masonry瀑布流布局神器使用详解
2017/05/25 jQuery
微信小程序实现左滑修改、删除功能
2020/10/19 Javascript
配置node服务器并且链接微信公众号接口配置步骤详解
2019/06/21 Javascript
微信小程序调用天气接口并且渲染在页面过程详解
2019/06/24 Javascript
Vue中computed和watch有哪些区别
2020/12/19 Vue.js
[03:40]DOTA2亚洲邀请赛小组赛第二日 赛事回顾
2015/01/31 DOTA
浅析python中的迭代与迭代对象
2018/10/08 Python
python如何给字典的键对应的值为字典项的字典赋值
2019/07/05 Python
python3.6中@property装饰器的使用方法示例
2019/08/17 Python
Python如何实现强制数据类型转换
2019/11/22 Python
python返回数组的索引实例
2019/11/28 Python
Python2与Python3的区别点整理
2019/12/12 Python
自定义实现 PyQt5 下拉复选框 ComboCheckBox的完整代码
2020/03/30 Python
Python实现自动装机功能案例分析
2020/10/22 Python
浅谈html5之sse服务器发送事件EventSource介绍
2017/08/28 HTML / CSS
Links of London官方网站:英国标志性的珠宝品牌
2017/04/09 全球购物
英国最大的美妆产品在线零售商之一:Beauty Bay
2017/09/29 全球购物
Topshop法国官网:英国快速时尚品牌
2018/04/08 全球购物
Lulu Guinness露露·吉尼斯官网:红唇包
2019/02/03 全球购物
数据库专业英语
2012/11/30 面试题
大学自荐信
2013/12/12 职场文书
预备党员思想汇报范文
2014/01/11 职场文书
Python 多线程之threading 模块的使用
2021/04/14 Python
详解JSON.parse和JSON.stringify用法
2022/02/18 Javascript
 分享一个Python 遇到数据库超好用的模块
2022/04/06 Python