首先深拷贝和浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样,也就是地址的复制还是值的复制的区别。

什么是可变对象,什么是不可变对象:

可变对象是指,一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值;

不可变对象是指,一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象指向的值复制出来一份,然后做了修改后存到另一个地址上了,但是可变对象就不会做这样的动作,而是直接在对象所指的地址上把值给改变了,而这个对象依然指向这个地址。

深拷贝和浅拷贝需要注意的地方就是可变元素的拷贝:

在浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样,这个是浅拷贝相对于深拷贝最根本的区别。

举例说明:

#encoding=utf-8

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

a.append(6)#修改对象a
a[5].append('c')#修改对象a中的['a','b']数组对象
print "a=",a,"    id(a)=",id(a),"id(a[5])=",id(a[5])
print "b=",b,"    id(b)=",id(b),"id(b[5])=",id(b[5])
print "c=",c,"       id(c)=",id(c),"id(c[5])=",id(c[5])
print "d=",d,"            id(d)=",id(d),"id(d[5])=",id(d[5])

结果:

从程序的结果来看,列表a和b是赋值操作,两个对象完全指向同一个地址,a和b就是同一块地址的两个引用,其实就是一个东西,所以一个对象在修改浅层元素(不可变)或深层元素(可变)时,另一个对象也同时在变;

c是a进行浅拷贝生成的对象,可以看到a(或b)和c两个对象整体的id是不同的,但是里面的第5个元素-列表的地址却是相同的(指向同一个地址),所以b在浅层次元素层面(不可变)增加一个元素时,c并没跟着增加,但是b的第5个元素-列表在增加一个元素时,c的第5个元素也跟着增加了,这就是因为b和c的第5个元素-列表是指向同一个地址的,这个地址上的值变了,在两个地方会同时改变;

再看d,d的浅层次元素(不可变)和 深层次元素(可变)的地址和a,b,c都不一样,所以,a,b,c无论怎么修改,d都不会跟着改变,这就是深拷贝的结果。

也可以这样理解:

深拷贝就是完全跟以前就没有任何关系了,原来的对象怎么改都不会影响当前对象

浅拷贝,原对象的list元素改变的话会改变当前对象,如果当前对象中list元素改变了,也同样会影响原对象。

浅拷贝就是藕断丝连

深拷贝就是离婚了

通常复制的时候要用深拷贝,因为浅拷贝后,两个对象中不可变对象指向不同地址,相互不会改变,但是两个对象中的可变元素是指向相同的地址,一个变了,另一个会同时改变,会有影响(list是可变对象)。

如果要让原list和copy list没有影响怎么办?

用深拷贝,拷贝后完全开辟新的内存地址来保存之前的对象,虽然可能地址执行的内容可能相同(同一个地址,例如’s’),但是不会相互影响。

比如:

List1=[‘a’,’b’,’c’]

List2=[‘a’,’b’,’c’]

两个列表中的’a’的地址是相同的

Id(list1[0])=id(list2[0]),但是两个列表的地址是不同的

通常来讲不可变元素包含:

int,float,complex,long,str,unicode,tuple

python深拷贝和浅拷贝的区别的更多相关文章

  1. Python 深拷贝和浅拷贝的区别

    python的复制,深拷贝和浅拷贝的区别    在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用  ...

  2. 【python测试开发栈】—理解python深拷贝与浅拷贝的区别

    内存的浅拷贝和深拷贝是面试时经常被问到的问题,如果不能理解其本质原理,有可能会答非所问,给面试官留下不好的印象.另外,理解浅拷贝和深拷贝的原理,还可以帮助我们理解Python内存机制.这篇文章将会通过 ...

  3. python深拷贝与浅拷贝的区别

    可变对象:一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值 不可变对象:一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象 ...

  4. Python深拷贝与浅拷贝区别

    可变类型 如list.dict等类型,改变容器内的值,容器地址不变. 不可变类型 如元组.字符串,原则上不可改变值.如果要改变对象的值,是将对象指向的地址改变了 浅拷贝 对于可变对象来说,开辟新的内存 ...

  5. Python深拷贝和浅拷贝

    1- Python引用计数[1] 1.1 引用计数机制 引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象.内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的 ...

  6. Python赋值语句与深拷贝、浅拷贝的区别

    参考:http://stackoverflow.com/questions/17246693/what-exactly-is-the-difference-between-shallow-copy-d ...

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

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

  8. python 深拷贝与浅拷贝

    浅拷贝的方式有: lst=[1,2,3] (1)直接赋值: lst_cp = lst (2)for循环遍历生成:lst_cp= [i for i in lst] (3)copy模块下,copy.cop ...

  9. c# 深拷贝与浅拷贝的区别分析及实例

    浅拷贝(影子克隆):只复制对象的基本类型,对象类型,仍属于原来的引用. 深拷贝(深度克隆):不紧复制对象的基本类,同时也复制原对象中的对象.就是说完全是新对象产生的. 深拷贝是指源对象与拷贝对象互相独 ...

随机推荐

  1. 帝国cms如何调用指定id的文章到首页?

    小美女用帝国cms建了一个站,现在首页调出指定id为12的文章作为推荐,附带文章摘要,她想用代码的形式直接掉用,以后方便修改.那么,帝国cms如何调用指定id的文章呢?指定信息id,不是调用指定栏目i ...

  2. 20170725 Python 必须使用的Url编码

    -- 1 原因:在进行API 调用传参时,如果出现了和区分参数标识一样的特殊字符,那么就需要编码来作用 或者,传递的参数有敏感数据. 我的目的: Python开发的接口,C#调用传递参数 先用C# 进 ...

  3. RestFramework——API设计规范

    what's the RESTful RestFramework是一个能快速为我们提供API接口,方便我们编程的框架.API是后端编程人员写的,为了让前端拿数据的一个接口,通常就是以url的形式存在. ...

  4. jmeter报错:内存溢出

    使用jmeter进行压力测试时,经常会遇到内存溢出错误: 2018-08-28 09:01:26,686 ERROR o.a.j.JMeter: Uncaught exception: java.la ...

  5. 安卓端数据导出成txt文件

    toExport() { if (this.dataList == false) { this.$createDialog({ type: "alert", content: &q ...

  6. Cartographer源码阅读(1):程序入口

    带着几个思考问题: (1)IMU数据的使用,如何融合,Kalman滤波? (2)图优化的具体实现,闭环检测的策略? (3)3D激光的接入和闭环策略? 1. 安装Kdevelop工具: http://b ...

  7. eclipse中Tomcat服务器缓存位置,以及清理Tomcat缓存

    在Eclipse中进行Web开发,一般都会将项目直接在Eclipse中的Tomcat服务器运行,有时候修改了程序和页面之后,运行结果还是原来的 tomcat服务器中缓存的程序或者页面,需要清理缓存之后 ...

  8. css3径向渐变

    #grad2 { height: 440px; width: 440px; border-radius: %; background: -webkit-radial-gradient(closest- ...

  9. xcode 定义自己的代码片段

    个人修改后的github地址:https://github.com/jiangys/xcode_tool 电脑xcode存放的路径:~/Library/Developer/Xcode/UserData ...

  10. vue中强制刷新的bug处理

    vue是单页面应用,跳转路由也是局部刷新,这里就拿后台管理系统而言,如果你的后台管理系统是左右布局,你不会遇到这样的问题,但是如果你的后台管理系统是上左右布局,你就会遇到这个问题,一级菜单在最上面,二 ...