Python中的赋值、浅拷贝、深拷贝介绍


Posted in Python onMarch 09, 2015

和很多语言一样,Python中也分为简单赋值、浅拷贝、深拷贝这几种“拷贝”方式。

在学习过程中,一开始对浅拷贝理解很模糊。不过经过一系列的实验后,我发现对这三者的概念有了进一步的了解。

一、赋值

赋值算是这三种操作中最常见的了,我们通过一些例子来分析下赋值操作:

str例

>>> a = 'hello'

>>> b = 'hello'

>>> c = a

>>> [id(x) for x in a,b,c]

[4404120000, 4404120000, 4404120000]

由以上指令中,我们可以发现a, b, c三者的地址是一样的。所以以上赋值的操作就相当于c = a = b = 'hello'。

赋值是系统先给一个变量或者对象(这里是'hello')分配了内存,然后再将地址赋给a, b, c。所以它们的地址是相同的。

list例

>>> a = ['hello']

>>> b = ['hello']

>>> c = a

>>> [id(x) for x in a,b,c]

[4403975952, 4404095096, 4403975952]

但是这种情况却不一样了,a和b的地址不同。为何?

因为str是不可变的,所以同样是'hello'只有一个地址,但是list是可变的,所以必须分配两个地址。

这时,我们希望探究以上两种情况如果 修改值 会如何?

str例

>>> a = 'world'

>>> [id(x) for x in a,b,c]

[4404120432, 4404120000, 4404120000]

>>> print a, b, c

world hello hello

这时a的地址和值变了,但是b, c地址和值都未变。因为str的不可变性,a要重新赋值则需重新开辟内存空间,所以a的值改变,a指向的地址改变。b, c由于'hello'的不变性,不会发生改变。

list例

>>> a[0] = 'world'

>>> [id(x) for x in a,b,c]

[4403975952, 4404095096, 4403975952]

>>> print a, b, c

['world'] ['hello'] ['world']

这时a, c的值和地址均改变,但二者仍相同,b不改变。由于list的可变性,所以修改list的值不需要另外开辟空间,只需修改原地址的值。所以a, c均改变。

在了解了以上的不同点之后,我们就能很好地分析浅拷贝和深拷贝了。

我们均用list作为例子。

二、浅拷贝

>>> a = ['hello', [123, 234]]

>>> b = a[:]

>>> [id(x) for x in a,b]

[4496003656, 4496066752]

>>> [id(x) for x in a]

[4496091584, 4495947536]

>>> [id(x) for x in b]

[4496091584, 4495947536]

Line3,4可以看出a, b地址不同,这符合list是可变的,应开辟不同空间。那浅拷贝就是拷贝了一个副本吗?再看Line5 - 8,我们发现a, b中元素的地址是相同的。如果说字符串'hello'地址一致还能理解,但是第二个元素是list地址仍一致。 这就说明了浅拷贝的特点,只是将容器内的元素的地址复制了一份 。

接着我们尝试修改a, b中的值:

>>> a[0] = 'world'

>>> a[1].append(345)

>>> print 'a = ', a, '\n\r', 'b = ', b

a =  ['world', [123, 234, 345]] 

b =  ['hello', [123, 234, 345]]

a中第一个元素str改变,但是b中未改变;a中第二个元素改变,b中也改变。这就符合不可变的对象修改会开辟新的空间,可变的对象修改不会开辟新空间。也进一步证明了 浅拷贝仅仅是复制了容器中元素的地址 。

三、深拷贝

>>> from copy import deepcopy

>>> a = ['hello', [123, 234]]

>>> b = deepcopy(a)

>>> [id(x) for x in a, b]

[4496066824, 4496066680]

>>> [id(x) for x in a]

[4496091584, 4496067040]

>>> [id(x) for x in b]

[4496091584, 4496371792]

深拷贝后,可以发现a, b地址以及a, b中元素地址均不同。这才是完全 拷贝了一个副本 。

修改a的值后:

>>> a[0] = 'world'

>>> a[1].append(345)

>>> print 'a = ', a, '\n\r', 'b = ', b

a =  ['world', [123, 234, 345]] 

b =  ['hello', [123, 234]]

从Line4,5中可以发现仅仅a修改了,b没有任何修改。 因为b是一个完全的副本,元素地址均与a不同,a修改,b不受影响 。

总结:

1. 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 )。

2. 浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。

3. 深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。也就是说( 新瓶装新酒 )。

Python 相关文章推荐
Python 含参构造函数实例详解
May 25 Python
python WindowsError的错误代码详解
Jul 23 Python
python中文件变化监控示例(watchdog)
Oct 16 Python
python 将json数据提取转化为txt的方法
Oct 26 Python
使用Py2Exe for Python3创建自己的exe程序示例
Oct 31 Python
使用python画社交网络图实例代码
Jul 10 Python
python web框架 django wsgi原理解析
Aug 20 Python
Python爬虫之urllib基础用法教程
Oct 12 Python
浅谈Python中range与Numpy中arange的比较
Mar 11 Python
树莓派升级python的具体步骤
Jul 05 Python
Opencv python 图片生成视频的方法示例
Nov 18 Python
python process模块的使用简介
May 14 Python
Python自动连接ssh的方法
Mar 07 #Python
Python最长公共子串算法实例
Mar 07 #Python
Python复制目录结构脚本代码分享
Mar 06 #Python
python获取android设备的GPS信息脚本分享
Mar 06 #Python
Python写的英文字符大小写转换代码示例
Mar 06 #Python
Python脚本实现集群检测和管理功能
Mar 06 #Python
Python守护进程(daemon)代码实例
Mar 06 #Python
You might like
让你同时上传 1000 个文件 (一)
2006/10/09 PHP
简单的过滤字符串中的HTML标记
2006/12/25 PHP
php数组函数序列之array_splice() - 在数组任意位置插入元素
2011/11/07 PHP
PHP环境中Memcache的安装和使用
2015/11/05 PHP
thinkphp自带验证码全面解析
2016/09/18 PHP
thinkPHP多语言切换设置方法详解
2016/11/11 PHP
php原生导出excel文件的两种方法(推荐)
2016/11/19 PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
2017/11/17 PHP
TNC vs BOOM BO3 第二场2.13
2021/03/10 DOTA
JavaScript this 深入理解
2009/07/30 Javascript
ExtJS判断IE浏览器类型的方法
2014/02/10 Javascript
JS在IE下缺少标识符的错误
2014/07/23 Javascript
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
2014/09/26 NodeJs
zepto中使用swipe.js制作轮播图附swipeUp,swipeDown不起效果问题
2015/08/27 Javascript
简单实现JS对dom操作封装
2015/12/02 Javascript
JavaScript仿淘宝页面图片滚动加载及刷新回顶部的方法解析
2016/05/24 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
搭建element-ui的Vue前端工程操作实例
2018/02/23 Javascript
vue使用自定义icon图标的方法
2018/05/14 Javascript
微信小程序把百度地图坐标转换成腾讯地图坐标过程详解
2019/07/10 Javascript
js实现详情页放大镜效果
2020/10/28 Javascript
实例解析Python中的__new__特殊方法
2016/06/02 Python
Python的numpy库中将矩阵转换为列表等函数的方法
2018/04/04 Python
Python有参函数使用代码实例
2020/01/06 Python
tensorboard 可以显示graph,却不能显示scalar的解决方式
2020/02/15 Python
python统计mysql数据量变化并调用接口告警的示例代码
2020/09/21 Python
基于HTML5陀螺仪实现ofo首页眼睛移动效果的示例
2017/07/31 HTML / CSS
英国最大的专业户外零售商:Mountain Warehouse
2018/06/06 全球购物
计算机专业毕业生的自我评价
2013/11/18 职场文书
八年级生物教学反思
2014/01/22 职场文书
历史专业学生的自我评价
2014/02/28 职场文书
教师节横幅标语
2014/10/08 职场文书
新学期新寄语,献给新生们!
2019/11/15 职场文书
超级实用!五步法则,教你写好年终工作总结
2019/12/05 职场文书
vue组件的路由高亮问题解决方法
2021/05/11 Vue.js
SpringBoot2 参数管理实践之入参出参与校验的方式
2021/06/16 Java/Android