详解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利用urllib和urllib2访问http的GET/POST详解
Sep 27 Python
Python通过future处理并发问题
Oct 17 Python
selenium+python 去除启动的黑色cmd窗口方法
May 22 Python
selenium python 实现基本自动化测试的示例代码
Feb 25 Python
python通过SSH登陆linux并操作的实现
Oct 10 Python
用python介绍4种常用的单链表翻转的方法小结
Feb 24 Python
python+Selenium自动化测试——输入,点击操作
Mar 06 Python
解决echarts中饼图标签重叠的问题
May 16 Python
Python 远程开关机的方法
Nov 18 Python
python安装及变量名介绍详解
Dec 12 Python
Python调用高德API实现批量地址转经纬度并写入表格的功能
Jan 12 Python
解决hive中导入text文件遇到的坑
Apr 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去除HTML标签实例
2013/11/06 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
JavaScript 滚轮事件使用说明
2010/03/07 Javascript
修复IE9&safari 的sort方法
2011/10/21 Javascript
js中的异常处理try...catch使用介绍
2013/09/21 Javascript
js实现两个值相加alert出来精确到指定位
2013/09/25 Javascript
js操作输入框提示信息且响应鼠标事件
2014/03/25 Javascript
jQuery实现鼠标划过添加和删除class的方法
2015/06/26 Javascript
详解JavaScript逻辑And运算符
2015/12/04 Javascript
Bootstrap树形组件jqTree的简单封装
2016/01/25 Javascript
JS onkeypress兼容性写法详解
2016/04/27 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
前端框架Vue.js构建大型应用浅析
2016/09/12 Javascript
配置nodejs环境的方法
2017/05/13 NodeJs
使用 Javascript 实现浏览器推送提醒功能的示例
2017/11/03 Javascript
vue删除html内容的标签样式实例
2018/09/13 Javascript
详解Vue项目中出现Loading chunk {n} failed问题的解决方法
2018/09/14 Javascript
Python中多线程thread与threading的实现方法
2014/08/18 Python
Python编程入门之Hello World的三种实现方式
2015/11/13 Python
python实现用户管理系统
2018/01/10 Python
python实现AES和RSA加解密的方法
2019/03/28 Python
Python获取excel内容及相关操作代码实例
2020/08/10 Python
Tostadora意大利:定制T恤
2019/04/08 全球购物
旅游与酒店管理的自我评价分享
2013/11/03 职场文书
工作中个人的自我评价
2013/12/31 职场文书
施工资料员岗位职责
2014/01/06 职场文书
青年教师典范事迹材料
2014/01/31 职场文书
2014年道德讲堂实施方案
2014/03/05 职场文书
美丽乡村建设实施方案
2014/03/23 职场文书
诚实守信道德模范事迹材料
2014/08/15 职场文书
党的群众路线教育实践活动对照检查材料范文
2014/09/24 职场文书
我的法兰西岁月观后感
2015/06/09 职场文书
八年级物理教学反思
2016/02/19 职场文书
2019年中学生的思想品德评语集锦
2019/12/19 职场文书
Golang 并发下的问题定位及解决方案
2022/03/16 Golang
postgresql之greenplum字符串去重拼接方式
2023/05/08 PostgreSQL