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的While循环语句的使用方法
Oct 13 Python
python安装与使用redis的方法
Apr 19 Python
使用Python从零开始撸一个区块链
Mar 14 Python
Python中关键字global和nonlocal的区别详解
Sep 03 Python
解决每次打开pycharm直接进入项目的问题
Oct 28 Python
python读取目录下最新的文件夹方法
Dec 24 Python
python使用pymongo操作mongo的完整步骤
Apr 13 Python
python 怎样将dataframe中的字符串日期转化为日期的方法
Sep 26 Python
基于Python实现拆分和合并GIF动态图
Oct 22 Python
利用Python小工具实现3秒钟将视频转换为音频
Oct 29 Python
关于Numpy中的行向量和列向量详解
Nov 30 Python
Python List remove()实例用法详解
Aug 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
在Windows中安装Apache2和PHP4的权威指南
2006/10/09 PHP
php MySQL与分页效率
2008/06/04 PHP
第4章 数据处理-php数组的处理-郑阿奇
2011/07/04 PHP
深入分析PHP引用(&)
2014/09/04 PHP
PHP文件锁函数flock()详细介绍
2014/11/18 PHP
php循环table实现一行两列显示的方法
2015/06/04 PHP
PHP内核学习教程之php opcode内核实现
2016/01/27 PHP
PHP实现的简单路由和类自动加载功能
2018/03/13 PHP
用js实现table单元格高宽调整,兼容合并单元格(兼容IE6、7、8、FF)实例
2013/06/25 Javascript
基于Unit PNG Fix.js有时候在ie6下不正常的解决办法
2013/06/26 Javascript
script不刷新页面的联动前后代码
2013/09/18 Javascript
详解javascript事件冒泡
2016/01/09 Javascript
只要1K 纯JS脚本送你一朵3D红色玫瑰
2016/08/09 Javascript
JS实现问卷星自动填问卷脚本并在两秒自动提交功能
2020/06/17 Javascript
JS中call和apply函数用法实例分析
2018/06/20 Javascript
layui点击导航栏刷新tab页的示例代码
2018/08/14 Javascript
vue3.0 CLI - 1 - npm 安装与初始化的入门教程
2018/09/14 Javascript
解决vue keep-alive 数据更新的问题
2018/09/21 Javascript
微信小程序使用canvas的画图操作示例
2019/01/18 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
vue 实现v-for循环回来的数据动态绑定id
2019/11/07 Javascript
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
2020/08/20 NodeJs
在Python的Flask中使用WTForms表单框架的基础教程
2016/06/07 Python
Python使用cx_Oracle模块操作Oracle数据库详解
2018/05/07 Python
python实现随机漫步算法
2018/08/27 Python
python脚本实现mp4中的音频提取并保存在原目录
2020/02/27 Python
python中使用you-get库批量在线下载bilibili视频的教程
2020/03/10 Python
日本卡普空电视游戏软件公司官方购物网站:e-CAPCOM
2018/07/17 全球购物
大学生的四年学习自我评价
2013/12/13 职场文书
应届毕业生个人求职自荐信
2014/01/06 职场文书
公司担保书范文
2014/05/21 职场文书
我们的节日国庆活动方案
2014/08/19 职场文书
学校个人对照检查材料
2014/08/26 职场文书
个人年终总结怎么写
2015/03/09 职场文书
2016年幼儿园庆六一开幕词
2016/03/04 职场文书
分享7个 Python 实战项目练习
2022/03/03 Python