详解Python直接赋值,深拷贝和浅拷贝


Posted in Python onJuly 09, 2020

直接赋值: 对象的引用,也就是给对象起别名
浅拷贝: 拷贝父对象,但是不会拷贝对象的内部的子对象。
深拷贝: 拷贝父对象. 以及其内部的子对象

在之前的文章中,提到可变对象和不可变对象,接下来也是以这两者的区别进行展开

直接赋值

对于可变对象和不可变对象,将一个变量直接赋值给另外一个变量,两者 id 值一致,其实本质上是将变量量绑定到对象的过程.

>>> a=1
>>> b=a
>>> id(a) == id(b)
True
>>> c="string"
>>> d=c
>>> id(c) == id(d)
True
>>> e=[1,2,3]
>>> f=e
>>> id(e)==id(f)
True

关于修改新变量的值,对原有变量会产生的影响,在可变对象和不可变对象 中也做了讲述,这里通过几个例子,重新温习一下

不可变对象

>>> x=1
>>> y=x
>>> id(x)==id(y)
True
>>> id(1)==id(y)
True
>>>>>> id(x)
1500143776
>>> y=y+1
>>> y
2
>>> x
1
>>> id(x)==id(y)
False
>>> id(y)
1500143808
>>> id(x)
1500143776

对于不可变对象,修改赋值后的新变量,不会对原有变量造成任何影响.为什么出现这种现象呢?因为不可变对象一旦创建之后就不允许被改变.后面对 y 进行的操作,其实是重新创建一个对象并绑定的结果:

详解Python直接赋值,深拷贝和浅拷贝

可变对象

>>> m=[1,2,3]
>>> n=m
>>> id(n)==id(m)
True
>>> id(m)
1772066764488
>>> id(n[0])
1772066764656
>>> n[0]=4
>>> n
[4, 2, 3]
>>> m
[4, 2, 3]
>>> id(n)==id(m)
True
>>> id(m)
1772066764488

对于可变对象,修改赋值后的变量,会对原有的变量造成影响,会导致其 value 值的改变,但是其id 值保持不变

详解Python直接赋值,深拷贝和浅拷贝

从上图不难看出,这个时候的 id(n[0]) 的值,和未修改前的 id值应该不一样,可以输出看一下

>>>id(n[0])
1772066764752 # 最初没有修改前是 1772066764656

n[0] 修改前后为什么 id 值出现改变呢? 首先需要明确一点 n[0] 绑定的是一个不可变对象,在文章的最初提到,不可变对象一旦创建就不允许修改.显然对 n[0] 进行修改,不能在绑定对象的内存上进行修改,那如何实现重新赋值呢?只能创建一个新的对象 4 ,然后将 n[0] 绑定到新的对象

浅拷贝和深拷贝

先看一下官方文档的定义

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or
class instances).
A shallow copy constructs a new compound object and then (to the
extent possible) inserts the same objects into it that the
original contains.
A deep copy constructs a new compound object and then, recursively,inserts copies into it of the objects found in the original.

从文档中不难看出,上面提到深拷贝和浅拷贝两者区别在于在复合对象,那接下来也只讨论复合对象.

浅拷贝

注意到官方文档也提到对浅拷贝和深拷贝的定义,从上文中不难看出,浅拷贝构建一个复合对象,然后将原有复合对象包含的对象插入到新的复合对象中

详解Python直接赋值,深拷贝和浅拷贝

从上图不难看出,浅拷贝后,新复合对象包含的对象(可变或者不可变)的 id 值和原有对象包含的对象的 id 值相同

看一下具体例子:

>>> import copy
>>> a=[1,2,[3,4]]
>>> b=copy.copy(a)
>>> id(b[0])==id(a[0])
True
>>> id(b[2])==id(a[2])
True
>>> id(b[2][0])==id(a[2][0])
True

现在让我们试着修改一下浅拷贝后的 b 的值,在修改前,可以先思考一下,如果修改 b[0] 可能会发生什么?

由于 b[0] = 1,很显然 1 属于不可变对象,那么根据对不可变变量修改的规则,则 b[0] 会绑定到新的变量上,而 a[0] 的由于没有修改,则保持不变,真的是这样吗?让我们验证一下

>>> b[0]=5
>>> b
[5, 2, [3, 4]]
>>> a
[1, 2, [3, 4]]

接下来我们要尝试修改一下 b[2],由于 b[2] 绑定的对象是 list,属于可变对象,按照上面说的可变对象修改的规则,则修改后的 b[2]id 值保持不变,但是其 value 值会发生改变. 同样的让我们通过例子验证一下

>>> id(b[2])
4300618568
>>> b[2][0]=6
>>> id(b[2])
4300618568
>>> b
[5, 2, [6, 4]]
>>> a
[1, 2, [6, 4]]

由于 b[2]a[2] 绑定同一个可变对象,很显然对 b[2] 的修改同样会映射到 a[2]

深拷贝

深拷贝构建一个复合对象,然后递归的将原有复合包含的对象的副本插入到新的复合对象中

详解Python直接赋值,深拷贝和浅拷贝

若上图所示,深拷贝后,新的复合对象包含的对象,若对象为不可变对象,则 id 值保持不变,若对象为可变对象,则 id 值发生改变

看一个例子:

>>> import copy
>>> a=[1,2,[3,4]]
>>> b=copy.deepcopy(a)
>>> id(b[0])==id(a[0])
True
>>> id(b[2])==id(a[0])
False
>>> id(b[2][0])==id(a[2][0])
True

接下来让我们修改一下变量 b,这里就不在修改不可变对象 b[0]b[1] 了,因为结果很明显,对 a 不会产生任何影响,我们来修改 b[2],那么修改 b[2] 会对 a[2] 产生影响吗?很明显答案是不会,因为深拷贝就相当于克隆出了一个全新的个体,两者不再有任何关系

>>> b[2][0]=5
>>> b
[1, 2, [5, 4]]
>>> a
[1, 2, [3, 4]]

以上就是详解Python直接赋值,深拷贝和浅拷贝的详细内容,更多关于Python直接赋值,深拷贝和浅拷贝的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python中模块查找的原理与方法详解
Aug 11 Python
一篇文章搞懂Python的类与对象名称空间
Dec 10 Python
详解Python进阶之切片的误区与高级用法
Dec 24 Python
对python中矩阵相加函数sum()的使用详解
Jan 28 Python
Django csrf 两种方法设置form的实例
Feb 03 Python
详解python中@的用法
Mar 27 Python
numpy库与pandas库axis=0,axis= 1轴的用法详解
May 27 Python
python+opencv实现摄像头调用的方法
Jun 22 Python
在Python中预先初始化列表内容和长度的实现
Nov 28 Python
对tensorflow中的strides参数使用详解
Jan 04 Python
Python关于OS文件目录处理的实例分享
May 23 Python
Python实现数据的序列化操作详解
Jul 07 Python
使用python实现下载我们想听的歌曲,速度超快
Jul 09 #Python
Python selenium模块实现定位过程解析
Jul 09 #Python
Python自动化操作实现图例绘制
Jul 09 #Python
解决pip install psycopg2出错问题
Jul 09 #Python
利用python下载scihub成文献为PDF操作
Jul 09 #Python
Python scrapy爬取小说代码案例详解
Jul 09 #Python
使用Python实现微信拍一拍功能的思路代码
Jul 09 #Python
You might like
php 5.3.5安装memcache注意事项小结
2011/04/12 PHP
PHP+Mysql实现多关键字与多字段生成SQL语句的函数
2014/11/05 PHP
php查找字符串出现次数的方法
2014/12/01 PHP
javascript语句中的CDATA标签的意义
2007/05/09 Javascript
JavaScript中valueOf函数与toString方法深入理解
2012/12/02 Javascript
js图片延迟技术一般的思路与示例
2014/03/20 Javascript
js实现的点击div区域外隐藏div区域
2014/06/30 Javascript
Javascript中arguments对象详解
2014/10/22 Javascript
微信企业号开发之微信考勤Cookies的使用
2015/09/11 Javascript
原生JS实现幻灯片
2017/02/22 Javascript
React入门教程之Hello World以及环境搭建详解
2017/07/11 Javascript
React Native实现地址挑选器功能
2017/10/24 Javascript
vue.js $refs和$emit 父子组件交互的方法
2017/12/20 Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
2018/01/08 Javascript
vue element-ui 绑定@keyup事件无效的解决方法
2018/03/09 Javascript
jquery.onoff实现简单的开关按钮功能(推荐)
2018/05/24 jQuery
JavaScript函数apply()和call()用法与异同分析
2018/08/10 Javascript
在layui下对元素进行事件绑定的实例
2019/09/06 Javascript
使用VScode 插件debugger for chrome 调试react源码的方法
2019/09/13 Javascript
python self,cls,decorator的理解
2009/07/13 Python
python算法学习之计数排序实例
2013/12/18 Python
跟老齐学Python之开始真正编程
2014/09/12 Python
python构建自定义回调函数详解
2017/06/20 Python
numpy中以文本的方式存储以及读取数据方法
2018/06/04 Python
基于django channel实现websocket的聊天室的方法示例
2019/04/11 Python
浅谈多卡服务器下隐藏部分 GPU 和 TensorFlow 的显存使用设置
2020/06/30 Python
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
仓库门卫岗位职责
2013/12/22 职场文书
学校食堂食品安全责任书
2014/07/28 职场文书
社区娱乐活动方案
2014/08/21 职场文书
大学生自我评价200字(4篇)
2014/09/17 职场文书
钱塘江大潮导游词
2015/02/03 职场文书
退休教师追悼词
2015/06/23 职场文书
学习《中小学教师职业道德规范》心得体会
2016/01/18 职场文书
如何用python反转图片,视频
2021/04/24 Python
Linux中Nginx的防盗链和优化的实现代码
2021/06/20 Servers