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的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。

        

    

  

    

时间: 2024-08-24 06:37:43

python 中 深拷贝和浅拷贝的理解的相关文章

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

import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy.deepcopy(a) #对象拷贝,深拷贝 a.append(5) #修改对象a a[4].append('c') #修改对象a中的['a', 'b']数组对象 print 'a = ', a print 'b = ', b print 'c = ', c print 'd = ', d 输出为:a

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

Python中深拷贝与浅拷贝的区别: 原创 2017年04月20日 16:58:35 标签: python / python两种拷贝 / 深拷贝浅拷贝 / 拷贝区别 1661 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已. 浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已.也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制 深拷贝:外围和内部元素都进行了拷贝

浅析Python中深拷贝和浅拷贝

按照以下不同情况,在IDE中逐个解除注释,就明白了 import copy """ 第一种情况,不可变类型变量,都是引用 """ # a = 1 # a = (11, 222, 333) # a = 'string' # a = True # b = a # # print(id(a)) # print(id(b)) # # c =copy.copy(a) # d = copy.deepcopy(a) # print(id(c)) # print

oc中深拷贝与浅拷贝

shallow 浅拷贝       Deep深拷贝 1.产生一个新对象,对象的内容与源对象相同 2.源对象与新对象使用不同的内存区域 3.需要NSCopying 或者NSMutableCopying协议才能使用复制功能 ? 4.Fundation中得基础数据类型如Nsstring.NSNumber 等都实现了NSCopying 5.新对象的引用计数为1 6.copy与mutableCopy的区别 copy返回不可变对象(包括可变对象在内) ? mutableCopy返回可变对象 7.浅拷贝只复制

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简单阐述到栈堆,基本数据类型与引用数据类型,因为这些概念能更好的让你理解深拷贝与浅拷贝. 我们来举个浅拷贝例子: let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b); 嗯?明明b复

c++中深拷贝和浅拷贝问题

在C++中深拷贝和浅拷贝问题还是比较重要的,简单介绍一下深拷贝和浅拷贝的意思,在C++中类默认有六个函数,拷贝构造函数就包括在其中,对于在程序运行的过程中,如果程序中没有自定义拷贝构造函数,那么程序将会使用自己的默认构造函数,在这个过程中,称为浅拷贝,用户自定义的拷贝构造函数称为深拷贝. 以下面的实际例子来加以说明深拷贝和浅拷贝之间的主要区别: #include <iostream> #include<string> using namespace std; class A { p

Python中赋值、浅拷贝与深拷贝

python中关于对象复制有三种类型的使用方式,赋值.浅拷贝与深拷贝.他们既有区别又有联系,刚好最近碰到这一类的问题,研究下. 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不同.如下: list_a = [1,2,3,"hello",["python","C++"]] list_b = list_a 这种情况下,list_b和list_a是一样的,他们指向同一片内存,list_b不过是list_a的别名,是引用. 我们可

关于python中赋值、浅拷贝、深拷贝之间区别的深入分析

大家都知道,在python中复制一个对象有多种方法,其中常用的是赋值.浅拷贝和深拷贝,这三者之间有哪些区别和哪些坑呢? 首先,定义一下: 赋值:  a =1    b =a    a赋值给了b 浅拷贝: a = []  b = a.copy() 或者import copy             b = copy.copy(a) 深拷贝:import copy  a = []   b = copy.deepcopy(a) 未完待续

[py]python的深拷贝和浅拷贝

Python深复制浅复制or深拷贝浅拷贝 简单点说 copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. copy.deepcopy 深拷贝 拷贝对象及其子对象 用一个简单的例子说明如下: >>>import copy >>>a = [1, 2, 3, 4, ['a', 'b', 'c']] >>> b = a >>> c = copy.copy(a) >>> d = copy.deepcopy(a