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处理JSON数据并生成条形图
Aug 05 Python
Python实现将16进制字符串转化为ascii字符的方法分析
Jul 21 Python
Python 和 JS 有哪些相同之处
Nov 23 Python
Python语言描述最大连续子序列和
Dec 05 Python
Python实现扣除个人税后的工资计算器示例
Mar 26 Python
Ubuntu下使用python读取doc和docx文档的内容方法
May 08 Python
python3实现字符串的全排列的方法(无重复字符)
Jul 07 Python
Anaconda2 5.2.0安装使用图文教程
Sep 19 Python
Python paramiko模块使用解析(实现ssh)
Aug 30 Python
python hashlib加密实现代码
Oct 17 Python
Python变量、数据类型、数据类型转换相关函数用法实例详解
Jan 09 Python
设置jupyter中DataFrame的显示限制方式
Apr 12 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缩放图片(根据宽高的等比例缩放)实例介绍
2013/06/09 PHP
数组与类使用PHP的可变变量名需要的注意的问题
2013/06/20 PHP
php生成短网址示例
2014/05/05 PHP
基于jquery的无缝循环新闻列表插件
2011/03/07 Javascript
Jquery跳到页面指定位置的方法
2014/05/12 Javascript
javascript学习笔记之函数定义
2015/06/25 Javascript
jquery图片滚动放大代码分享(2)
2015/08/28 Javascript
jquery正则表达式验证(手机号、身份证号、中文名称)
2015/12/31 Javascript
JavaScript中省略元素对数组长度的影响
2016/10/26 Javascript
jQuery基于ajax实现页面加载后检查用户登录状态的方法
2017/02/10 Javascript
基于JavaScript实现轮播图原理及示例
2020/04/10 Javascript
angular4模块中给标签添加背景图的实现方法
2017/09/15 Javascript
详解Angular6 热加载配置方案
2018/08/18 Javascript
关于vue编译版本引入的问题的解决
2018/09/17 Javascript
简介Django中内置的一些中间件
2015/07/24 Python
Python实现简单网页图片抓取完整代码实例
2017/12/15 Python
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
2018/02/23 Python
python实现读取大文件并逐行写入另外一个文件
2018/04/19 Python
Python利用heapq实现一个优先级队列的方法
2019/02/03 Python
使用python来调用CAN通讯的DLL实现方法
2019/07/03 Python
Python从文件中读取指定的行以及在文件指定位置写入
2019/09/06 Python
python BlockingScheduler定时任务及其他方式的实现
2019/09/19 Python
Python3 实现爬取网站下所有URL方式
2020/01/16 Python
泰海淘:泰国king Power王权免税集团旗下跨境海淘综合型电商
2020/07/26 全球购物
市场营销专业个人求职信范文
2013/12/14 职场文书
生育关怀行动实施方案
2014/03/26 职场文书
不拖欠农民工工资承诺书
2014/03/31 职场文书
《画杨桃》教学反思
2014/04/13 职场文书
捐助倡议书范文
2014/04/15 职场文书
敬老模范事迹
2014/05/21 职场文书
2014年电教工作总结
2014/12/19 职场文书
淮阳太昊陵导游词
2015/02/10 职场文书
合同纠纷调解书
2015/05/20 职场文书
举起手来观后感
2015/06/09 职场文书
人为什么会“幸灾乐祸”?
2019/08/06 职场文书
导游词之丹东鸭绿江
2019/10/24 职场文书