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 sqlobject(mysql)中文乱码解决方法
Nov 14 Python
解决Python出现_warn_unsafe_extraction问题的方法
Mar 24 Python
Django卸载之后重新安装的方法
Mar 15 Python
python中reader的next用法
Jul 24 Python
Python 变量类型详解
Oct 10 Python
Python 忽略warning的输出方法
Oct 18 Python
pandas读取csv文件,分隔符参数sep的实例
Dec 12 Python
numpy ndarray 按条件筛选数组,关联筛选的例子
Nov 26 Python
pytorch进行上采样的种类实例
Feb 18 Python
Python如何使用input函数获取输入
Aug 06 Python
Python批量获取并保存手机号归属地和运营商的示例
Oct 09 Python
详解matplotlib中pyplot和面向对象两种绘图模式之间的关系
Jan 22 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
《逃离塔科夫》——“萌新劝退,老手自嗨”的硬核FPS游戏
2020/04/03 其他游戏
简单的php新闻发布系统教程
2014/05/09 PHP
Windows 下安装 swoole 图文教程(php)
2017/06/05 PHP
PHP实现统计代码行数小工具
2019/09/19 PHP
JS代码格式化和语法着色V2
2006/10/14 Javascript
实现JavaScript中继承的三种方式
2009/10/16 Javascript
获得所有表单值的JQuery实现代码[IE暂不支持]
2012/05/24 Javascript
JS调用页面表格导出excel示例代码
2014/03/18 Javascript
深入学习JavaScript中的Rest参数和参数默认值
2015/07/28 Javascript
jquery实现的Banner广告收缩效果代码
2015/09/02 Javascript
借助FileReader实现将文件编码为Base64后通过AJAX上传
2015/12/24 Javascript
javascript常见数字进制转换实例分析
2016/04/21 Javascript
Javascript中获取浏览器类型和操作系统版本等客户端信息常用代码
2016/06/28 Javascript
ES6新特性之Symbol类型用法分析
2017/03/31 Javascript
Vue.js实现一个SPA登录页面的过程【推荐】
2017/04/29 Javascript
vue 计时器组件的实现代码
2017/09/14 Javascript
微信小程序自定义select下拉选项框组件的实现代码
2018/08/28 Javascript
在Vuex中Mutations修改状态操作
2020/07/24 Javascript
vue 需求 data中的数据之间的调用操作
2020/08/05 Javascript
python获取当前时间对应unix时间戳的方法
2015/05/15 Python
Python 基础之字符串string详解及实例
2017/04/01 Python
用Python将一个列表分割成小列表的实例讲解
2018/07/02 Python
python--shutil移动文件到另一个路径的操作
2020/07/13 Python
python 基于Apscheduler实现定时任务
2020/12/15 Python
实习鉴定范文
2013/12/19 职场文书
关于环保的演讲稿
2014/05/10 职场文书
敬老院院长事迹材料
2014/05/21 职场文书
市级青年文明号申报材料
2014/05/26 职场文书
普通党员个人整改措施
2014/10/27 职场文书
解除劳动合同证明书模板
2014/11/20 职场文书
升职自我推荐信范文
2015/03/25 职场文书
工作简报怎么写
2015/07/21 职场文书
《圆的面积》教学反思
2016/02/19 职场文书
2017公司年会主持人开幕词
2016/03/04 职场文书
浅谈redis整数集为什么不能降级
2021/07/25 Redis
JavaScript实现栈结构详细过程
2021/12/06 Javascript