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中赋 ...
随机推荐
- 原生+jquery 实现好看滚动条。
//原生 <!doctype html> <html> <head> <meta charset="utf-8"> <titl ...
- 黄聪:PHP7.0中htmlspecialchars出错解决方案(wordpress)
htmlspecialchars( $context, ENT_COMPAT, 'UTF-8' )
- UVA 247 电话圈(Floyd传递闭包+输出连通分量)
电话圈 紫书P365 [题目链接]电话圈 [题目类型]Floyd传递闭包+输出连通分量 &题解: 原来floyd还可以这么用,再配合连通分量,简直牛逼. 我发现其实求联通分量也不难,就是for ...
- 45. Scramble String
Scramble String Given a string s1, we may represent it as a binary tree by partitioning it to two no ...
- [VB.NET]调用系统的文件夹选择对话框
以下示例代码展示如何调用系统的文件夹选择对话框: Private Function SelectFolder(ByVal Describe As String, Optional ByVal Show ...
- 创建线程方式-GCD
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- 用于列出选项的Windows窗体控件
可以提供选项列表的控件有ListBox.ComboBox.CheckedListBox,如何正确的使用和选择这些控件,下面对此进行讨论.首先对这三种控件的功能分别进行说明: ListBox ListB ...
- c# 支付宝查单补单
谁谁谁手机那边支付宝支付成功扣钱了,游戏里面却没有充钱,唯有写个补单程序. 首先要查单,查单接口(交易信息查询接口:https://mapi.alipay.com/gateway.do),服务名称:s ...
- sql 2008 R2添加对MySql的远程服务器链接
(1).我的sql 2008 R2所在的系统为Windows server 2008 *64 (2).MySQL所在的系统为Windows server 2003 *86 我想要实现的是在sql 20 ...
- EXT学习之——EXT下拉框默认绑定第一个值
//默认第一个下拉框绑定值if (this.moduleCombo.store.getAt(0) != undefined) { this.moduleCombo.setValue(this.modu ...