在总结 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 中 深拷贝和浅拷贝的理解的更多相关文章

  1. 关于Python中深拷贝与浅拷贝的理解(一)---概念

    import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...

  2. python中深拷贝和浅拷贝

    python中所谓浅拷贝就是对引用的拷贝,所谓深拷贝就是对对象的资源的拷贝. 首先,对赋值操作我们要有以下认识: 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 ). 修改不可变 ...

  3. Python中深拷贝与浅拷贝的区别

    转自:http://blog.csdn.net/u014745194/article/details/70271868 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给 ...

  4. python中深拷贝与浅拷贝

    # 1.浅拷贝(复制东西)a = [11,22,33] # 实际上是浅拷贝# 没有把这个变量的值赋进去,而是把另一个变量的地址拿过去了,就叫浅拷贝.b = a # print(id(a))# prin ...

  5. python 中深拷贝和浅拷贝的区别

    通俗的理解,浅就是外面,深就是里面.浅拷贝的意思就是只拷贝外面的一层,深拷贝就是拷贝的里面的所有. 看两段代码: 元组: #!/usr/bin/env/python # -*-coding:utf-8 ...

  6. Python中深拷贝与浅拷贝区别

    浅拷贝, list值是可变的,str值不可变,只能重新赋值 a=b=c='wjx'print(a,b,c)c= 'jmy'#重新赋值了,所以内存分配了新的地址print(a,b,c)print(id( ...

  7. python中self cls init的理解

    原创文章,未经允许禁止转载! python中self cls init的理解 python中self cls init的理解

  8. 图解python中赋值、浅拷贝、深拷贝的区别

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果.下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will = ...

  9. python中赋值和浅拷贝与深拷贝

    初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...

随机推荐

  1. (C#) 求两个数组的交集

    基本上在面试的时候,会具体到两个int数组,或string数组.具体也就是讨论算法. 首先需要的是和面试的人确认题目的含义,并非直接答题. 然后,可以提出自己的想法,首先最快的是用linq { Lis ...

  2. MapReduce编程job概念原理

    在Hadoop中,每个MapReduce任务都被初始化为一个job,每个job又可分为两个阶段:map阶段和reduce阶段.这两个阶段分别用两个函数来表示.Map函数接收一个<key,valu ...

  3. 文件大boss

    1.write()  写命令 f=open("a2.txt",'w',encoding='utf-8') f.write() f.close() 2.closed  判断是否是关闭 ...

  4. maven-bundle-plugin 2.4.0以下版本导出META-INF中的内容到MANIFEST.MF中

    今天终于把maven-bundle-plugin不能导出META-INF中的内容到Export-Package中的问题解决了,因为用到的第三方JAR包需要加载META-INF/XX/XX.xml这个内 ...

  5. NHibernate和 FluentNHibernate

    NHibernate有两类配置文件,一个是数据库连接配置文件(一般写到程序配置文件里),另一个是数据表和实体的映射文件(实体类.hbm.xml) 开源的框架Fluent NHibernate,有了它, ...

  6. c语言实现二维数组排序,一个4*5的数组,要求每行都进行升序排列,并求出每行的平均值。

    #include<stdio.h>#define N 5#define M 4void main(){ int x,i,j,k,t,a[M][N]; float sum=0.0; floa ...

  7. CRM 2016 级联过滤

    以下以省市为例: function preFilterLookup() { //要进行过滤的lookup按钮加入addPresearch事件 Xrm.Page.getControl("shi ...

  8. iBeacon知识1

    iBeacon的数据主要由四种资讯构成,分别是UUID(通用唯一标识符).Major.Minor.Measured Power. UUID是规定为ISO/IEC11578:1996标准的128位标识符 ...

  9. cookie sessionStorage localStorage 区别

    sessionStorage 和 localStorage 是HTML5 Web Storage API 提供的,可以方便的在web请求之间保存数据.有了本地数据,就可以避免数据在浏览器和服务器间不必 ...

  10. NHibernate系列文章十二:Load/Get方法

    摘要 NHibernate提供两个方法按主键值查找对象:Load/Get. 1. Load/Get方法的区别 Load: Load方法可以对查询进行优化. Load方法实际得到一proxy对象,并不立 ...