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 相关文章推荐
python3模拟百度登录并实现百度贴吧签到示例分享(百度贴吧自动签到)
Feb 24 Python
Python的Socket编程过程中实现UDP端口复用的实例分享
Mar 19 Python
python 容器总结整理
Apr 04 Python
谈谈python中GUI的选择
Mar 01 Python
Python格式化日期时间操作示例
Jun 28 Python
python字典的setdefault的巧妙用法
Aug 07 Python
Django框架序列化与反序列化操作详解
Nov 01 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
Dec 11 Python
Python基于Dlib的人脸识别系统的实现
Feb 26 Python
Django media static外部访问Django中的图片设置教程
Apr 07 Python
pandas按条件筛选数据的实现
Feb 20 Python
Python OpenCV超详细讲解调整大小与图像操作的实现
Apr 02 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
收音机怀古---春雷3P7图片欣赏
2021/03/02 无线电
php对gzip文件或者字符串解压实例参考
2008/07/25 PHP
支持生僻字且自动识别utf-8编码的php汉字转拼音类
2014/06/27 PHP
制作安全性高的PHP网站的几个实用要点
2014/12/30 PHP
微信开发之网页授权获取用户信息(二)
2016/01/08 PHP
PHP使用第三方即时获取物流动态实例详解
2017/04/27 PHP
JS日历 推荐
2006/12/03 Javascript
js tab 选项卡
2009/04/26 Javascript
js 自定义的联动下拉框
2010/02/07 Javascript
js跨浏览器实现将字符串转化为xml对象的方法
2013/09/25 Javascript
自己实现ajax封装示例分享
2014/04/01 Javascript
js 判断图片是否加载完以及实现图片的预下载
2014/08/14 Javascript
jQuery实现带动画效果的二级下拉导航方法
2015/03/11 Javascript
javascript学习小结之prototype
2015/12/03 Javascript
Javascript实现前端简单的路由实例
2016/09/11 Javascript
ReactJs快速入门教程(精华版)
2016/11/28 Javascript
JavaScript的事件机制详解
2017/01/17 Javascript
bootstrap table 多选框分页保留示例代码
2017/03/08 Javascript
JavaScript实现body内任意节点的自定义属性功能示例
2017/09/18 Javascript
vue select选择框数据变化监听方法
2018/08/24 Javascript
js 实现ajax发送步骤过程详解
2019/07/25 Javascript
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
python操作MongoDB基础知识
2013/11/01 Python
Python利用itchat库向好友或者公众号发消息的实例
2019/02/21 Python
HTML5录音实践总结(Preact)
2020/05/07 HTML / CSS
为有想象力的人提供的生活方式商店:Firebox
2018/06/04 全球购物
武汉瑞得软件笔试题
2015/10/27 面试题
副职竞争上岗演讲稿
2014/05/12 职场文书
班组建设经验交流材料
2014/05/12 职场文书
保护环境倡议书300字
2014/05/19 职场文书
超市创业计划书
2014/09/15 职场文书
2015年元旦晚会活动总结(学生会)
2014/11/28 职场文书
茶楼服务员岗位职责
2015/02/09 职场文书
开票员岗位职责
2015/02/12 职场文书
合同补充协议书
2016/03/24 职场文书
详解python网络进程
2021/06/15 Python