python 中 深拷贝和浅拷贝的理解
在总结 python 对象和引用的时候,想到其实 对于python的深拷贝和浅拷贝也可以很好对其的进行理解。
在python中,对象的赋值的其实就是对象的引用。也就是说,当创建一个对象,然后赋给另外一个变量之后,实际上只是拷贝了这个对象的引用。
我们先用 利用切片操作和工厂方法list方法 来阐述一下浅拷贝。
举个栗子:
Tom = ['Tom', ['age', 10]]
Jack = Tom[:] ……切片操作
June = list(Tom)
接下来查看一下 上述三个变量的引用:
>>> id(Tom)
140466700697824
>>> id(Jack)
140466700700488
>>> id(June)
140466700770192
可以发现,三个变量分别指向了不同的对象。我们再来看一下这三个对象的内容:
>>> Tom
['Tom', ['age', 10]]
>>> Jack
['Tom', ['age', 10]]
>>> June
['Tom', ['age', 10]]
显然这三个对象的内容会是一样的,因为通过上面的 切片操作 以及 工厂函数list 对Tom引用的对象进行了拷贝。接下来再进行进一步验证:
我们对 Jack 和 June 引用的对象进行修改:
>>> Jack[0] = 'Jack'
>>> Jack
['Jack', ['age', 10]]
>>> June[0] = 'June'
>>> June
['June', ['age', 10]]
现在我们打算对Jack的年龄进行修改:
>>> Jack[1][1] = 20
>>> Jack
['Jack', ['age', 20]]
可以看到Jack年龄变为了20; 让我们接下来看一下Tom, June的年龄:
>>> print Tom, Jack, June
['Tom', ['age', 20]] ['Jack', ['age', 20]] ['June', ['age', 20]]
奇怪的事情发生了,我们仅仅是修改了 Jack的年龄, 但是Tom 和 June 的年龄跟着改变了, 这是为什么呢?
这个就涉及到了python中浅拷贝的奥秘:
我们先来看一下上面 Tom, Jack, June中内部元素的 内存地址:
>>> for x in Tom:
... print id(x)
...
140704715293600 --> 'Tom'
140704715147816 --> ['age', 20]
>>> for x in Jack:
... print id(x)
...
140704715286256 --> 'Jack'
140704715147816 --> ['age', 20]
>>> for x in June:
... print id(x)
...
140704715286352 -->'June'
140704715147816 -->['age', 20]
仔细观察可以看到,Tom, Jack, June 三个变量的 岁数元素['age', 20] 指向同一个 对象; 那为什么他们的 名字元素 分别指向不同的对象。这是因为,在python中的分为 可变数据对象(列表,字典) 和 不可变数据对象(整型,字符串,浮点型,元祖)。 正是因为这个原因,他们的 名字元素 为字符串,为不可变数据对象,因此开始为 Jack 和 June 重新命名的时候,实际上内存中已经创建了 Jack 和 June对象。而 岁数元素 是 可变数据对象,所以并不会在内存中创建新的对象,Tom,Jack,June的岁数元素都引用同一个对象,导致修改其中一个会让另外俩个的年龄跟着变化。
这个就是python的浅拷贝,其仅仅是拷贝了 一个整体的对象(应该说一个对象最外面的那一层),而对于对象里面包含的元素不会进行拷贝。
接下来,我们 利用copy中的deepcopy方法 来阐述一下 深拷贝:
还是用上面那个栗子:
为了让 Tom, Jack, June之间互不影响,我们用deepcopy方法对Tom进行拷贝生成 Jack 和 June:
>>> Tom = ['Tom', ['age', 10]]
>>> import copy
>>> Jack = copy.deepcopy(Tom)
>>> June = copy.deepcopy(Tom)
>>> Jack
['Tom', ['age', 10]]
>>> June
['Tom', ['age', 10]]
>>> Tom
['Tom', ['age', 10]]
让我们看一下Tom, Jack, June分别指向的内存地址:
>>> print id(Tom), id(June), id(Jack)
140707738759392 140707738799280 140707738797192
三个内存地址不同,然后我们接着改变Jack 和 June的名字,并查看修改后它们的内部元素所指向的内存地址:
>>> Jack[0] = 'Jack'
>>> June[0] = 'June'
>>> Tom
['Tom', ['age', 10]]
>>> Jack
['Jack', ['age', 10]]
>>> June
['June', ['age', 10]]
>>> for x in Tom:
... print id(x)
...
140707738882976 --> 'Tom'
140707738737192 --> ['age', 10]
>>> for x in Jack:
... print id(x)
...
140707738875584 --> 'Jack'
140707738910016 --> ['age', 10]
>>> for x in June:
... print id(x)
...
140707738876640 -->'June'
140707738910160 --> ['age', 10]
可以清楚的看到,他们的内部元素也指向了不同的对象,说明通过deepcopy方法,对元素进行了彻底的拷贝(包括内部元素)。
最后总结一下思路:
思路一:利用切片操作和工厂方法list方法拷贝就叫浅拷贝,只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。
思路二:利用copy中的deepcopy方法进行拷贝就叫做深拷贝,外围和内部元素都进行了拷贝对象本身,而不是引用。
但是对于数字,字符串和其他原子类型对象等,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。
python 中 深拷贝和浅拷贝的理解的更多相关文章
- 关于Python中深拷贝与浅拷贝的理解(一)---概念
import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...
- python中深拷贝和浅拷贝
python中所谓浅拷贝就是对引用的拷贝,所谓深拷贝就是对对象的资源的拷贝. 首先,对赋值操作我们要有以下认识: 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 ). 修改不可变 ...
- Python中深拷贝与浅拷贝的区别
转自:http://blog.csdn.net/u014745194/article/details/70271868 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给 ...
- python中深拷贝与浅拷贝
# 1.浅拷贝(复制东西)a = [11,22,33] # 实际上是浅拷贝# 没有把这个变量的值赋进去,而是把另一个变量的地址拿过去了,就叫浅拷贝.b = a # print(id(a))# prin ...
- python 中深拷贝和浅拷贝的区别
通俗的理解,浅就是外面,深就是里面.浅拷贝的意思就是只拷贝外面的一层,深拷贝就是拷贝的里面的所有. 看两段代码: 元组: #!/usr/bin/env/python # -*-coding:utf-8 ...
- Python中深拷贝与浅拷贝区别
浅拷贝, list值是可变的,str值不可变,只能重新赋值 a=b=c='wjx'print(a,b,c)c= 'jmy'#重新赋值了,所以内存分配了新的地址print(a,b,c)print(id( ...
- python中self cls init的理解
原创文章,未经允许禁止转载! python中self cls init的理解 python中self cls init的理解
- 图解python中赋值、浅拷贝、深拷贝的区别
Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果.下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will = ...
- python中赋值和浅拷贝与深拷贝
初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...
随机推荐
- java中&与&&的区别
我想很多人在学习java的时候,或者面试时都会遇到 &和&& 然而,如果你没有真正的理解他们的意思,这会给你思路上面带来很大的麻烦 在这篇blog中,当你看完了以后,你会发现, ...
- springmvc视图解析流程
无论目标方法返回String.VIew或者是ModelAndView,springmvc都会转化成ModelAndView 然后通过视图解析器(如InternalResouceViewResolver ...
- 【VB.NET】类绑定控件,实现文本框快捷键全选
Public Class KeyBinder Public Sub BindControl(ByRef CControl As TextBox) AddHandler CControl.KeyDown ...
- DEV中dx:ASPxPopupControl 控件的使用(在窗口关闭或隐藏时,清楚文本框中的内容)
//在窗口关闭或隐藏时,清楚文本框中的内容(核心代码) function(s, e) { ASPxClientEdit.ClearGroup('entryGroup'); } <asp:Cont ...
- 基于mini2440的boa服务器移植
win7 系统 开发板:mini2440 虚拟机:ubuntu12.04 准备工作:确保主机与开发板之间能够正常通信,即能够ping通,具体的操作课参考我上一篇随笔. 1.首先从 http://ww ...
- C++学习基础七——深复制与浅复制
一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深 ...
- linux部分命令
打包ROOT文件夹tar -cvf ROOT3.tar ./ROOT 解压则相反 ps aux | grep tomcat 直接杀死tomcat sudo kill -9 进程号 rm -rf ./R ...
- idea 到myeclipse
在上一篇博客使用maven进行开发过程管理之准备篇中提到了maven的基本概念.IT男罗书全觉得概念我是懂了,但是那些东西似乎离我很远啊.先开发再说吧, 于是IT男罗书全就在svn上取了源代码,并开始 ...
- 32、shiro框架入门3.授权
一. 授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等).在授权中需了解的几个关键对象:主体(Subject).资源(Resource).权限(Permission ...
- 关于web测试
关于web测试1页面部分(1) 页面清单是否完整(是否已经将所需要的页面全部都列出来了)(2) 页面是否显示(在不同分辨率下页面是否存在,在不同浏览器版本中页面是是否显示)(3) 页面在窗口中的显示是 ...