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二分法实现实例
Nov 21 Python
Python多线程编程(八):使用Event实现线程间通信
Apr 05 Python
理解python正则表达式
Jan 15 Python
想学python 这5本书籍你必看!
Dec 11 Python
PyTorch搭建多项式回归模型(三)
May 22 Python
Python机器学习算法库scikit-learn学习之决策树实现方法详解
Jul 04 Python
django框架两个使用模板实例
Dec 11 Python
tensorflow使用freeze_graph.py将ckpt转为pb文件的方法
Apr 22 Python
Python collections.defaultdict模块用法详解
Jun 18 Python
Python文件夹批处理操作代码实例
Jul 21 Python
Python模拟登录requests.Session应用详解
Nov 17 Python
详解BeautifulSoup获取特定标签下内容的方法
Dec 07 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
PHP 超链接 抓取实现代码
2009/06/29 PHP
php设计模式 Bridge (桥接模式)
2011/06/26 PHP
php XMLWriter类的简单示例代码(RSS输出)
2011/09/30 PHP
php explode函数实例代码
2012/02/27 PHP
WordPress中用于检索模版的相关PHP函数使用解析
2015/12/15 PHP
php制作简单模版引擎
2016/04/07 PHP
php 中phar包的使用教程详解
2018/10/26 PHP
php的instanceof和判断闭包Closure操作示例
2020/01/26 PHP
javascript静态的url如何传递
2007/05/03 Javascript
js数据验证集合、js email验证、js url验证、js长度验证、js数字验证等简单封装
2010/05/15 Javascript
JavaScript和CSS通过expression实现Table居中显示
2013/06/28 Javascript
Jquery获得控件值的三种方法总结
2014/02/13 Javascript
关于JavaScript对象的动态选择及遍历对象
2014/03/10 Javascript
JQuery右键菜单插件ContextMenu使用指南
2014/12/19 Javascript
jquery通过closest选择器修改上级元素的方法
2015/03/17 Javascript
js实现兼容IE、Firefox的图片缩放代码
2015/12/08 Javascript
jQuery 判断是否包含在数组中Array[]的方法
2016/08/03 Javascript
textarea 在浏览器中固定大小和禁止拖动的实现方法
2016/12/03 Javascript
原生JS京东轮播图代码
2017/03/22 Javascript
Bootstrap table使用方法记录
2017/08/23 Javascript
浅析Node.js非对称加密方法
2018/01/29 Javascript
vue动画之点击按钮往上渐渐显示出来的实例
2018/09/29 Javascript
浅谈一种让小程序支持JSX语法的新思路
2019/06/16 Javascript
vue页面加载时的进度条功能(实例代码)
2020/01/13 Javascript
JS async 函数的含义和用法实例总结
2020/04/08 Javascript
python实现文件名批量替换和内容替换
2014/03/20 Python
python逆序打印各位数字的方法
2018/06/25 Python
Django实现支付宝付款和微信支付的示例代码
2018/07/25 Python
Python并行分布式框架Celery详解
2018/10/15 Python
python实现比对美团接口返回数据和本地mongo数据是否一致示例
2019/08/09 Python
python自动化测试之异常及日志操作实例分析
2019/11/09 Python
html5小程序飞入购物车(抛物线绘制运动轨迹点)
2020/10/19 HTML / CSS
介绍一下木马病毒的种类
2015/07/26 面试题
客服端调用EJB对象的几个基本步骤
2012/01/15 面试题
高中毕业生登记表自我鉴定范文
2014/03/18 职场文书
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
2022/06/21 Golang