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 ORM框架SQLAlchemy学习笔记之关系映射实例
Jun 10 Python
Python实现命令行通讯录实例教程
Aug 18 Python
Python探索之修改Python搜索路径
Oct 25 Python
Python 查看文件的读写权限方法
Jan 23 Python
Python实现快速计算词频功能示例
Jun 25 Python
Pycharm更换python解释器的方法
Oct 29 Python
python实现多层感知器MLP(基于双月数据集)
Jan 18 Python
Python爬取数据保存为Json格式的代码示例
Apr 09 Python
django搭建项目配置环境和创建表过程详解
Jul 22 Python
基于Python实现ComicReaper漫画自动爬取脚本过程解析
Nov 11 Python
python 字典访问的三种方法小结
Dec 05 Python
Python类和实例的属性机制原理详解
Mar 21 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/10/21 PHP
PHP判断表单复选框选中状态完整例子
2014/06/24 PHP
[原创]ThinkPHP让../Public在模板不解析(直接输出)的方法
2015/10/09 PHP
laravel 5.1下php artisan migrate的使用注意事项总结
2017/06/07 PHP
在JavaScript中typeof的用途介绍
2013/04/11 Javascript
常用的Javascript数据验证插件
2015/08/04 Javascript
Angular 4.x中表单Reactive Forms详解
2017/04/25 Javascript
vue小图标favicon不显示的解决方案
2017/09/19 Javascript
React Native预设占位placeholder的使用
2017/09/28 Javascript
Vue中使用Sortable的示例代码
2018/04/07 Javascript
性能优化篇之Webpack构建速度优化的建议
2019/04/03 Javascript
layui监听select变化,以及设置radio选中的方法
2019/09/24 Javascript
基于vue+uniapp直播项目实现uni-app仿抖音/陌陌直播室功能
2019/11/12 Javascript
[44:26]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第二局
2016/03/03 DOTA
[57:09]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第一场 1月26日
2021/03/11 DOTA
使用C语言扩展Python程序的简单入门指引
2015/04/14 Python
Linux上使用Python统计每天的键盘输入次数
2019/04/17 Python
Python PyCharm如何进行断点调试
2019/07/05 Python
Python常见反爬虫机制解决方案
2020/06/01 Python
keras在构建LSTM模型时对变长序列的处理操作
2020/06/29 Python
带你学习Python如何实现回归树模型
2020/07/16 Python
python 实现"神经衰弱"翻牌游戏
2020/11/09 Python
Ted Baker英国官网:男士和女士服装及配件
2017/03/13 全球购物
开普敦通行证:Cape Town Pass
2019/07/18 全球购物
神路信息Java面试题目
2013/03/31 面试题
Java中的类包括什么内容?设计时要注意哪些方面
2012/05/23 面试题
一套Delphi的笔试题一
2016/02/14 面试题
自我鉴定范文
2013/11/10 职场文书
体育教师自我鉴定
2014/02/12 职场文书
金融学专业大学生职业生涯规划
2014/03/07 职场文书
党员自我对照检查材料
2014/08/19 职场文书
惹女朋友生气检讨书
2015/05/06 职场文书
工会文体活动总结
2015/05/07 职场文书
贫困证明书范文
2015/06/16 职场文书
拒绝盗图!教你怎么用python给图片加水印
2021/06/04 Python
利用python实时刷新基金估值(摸鱼小工具)
2021/09/15 Python