首先我在这介绍两个新的小知识:一个是函数 id() ,另一个是运算符 is。id() 函数就是返回对象的内存地址;is 是比较两个变量的对象引用是否指向同一个对象,在这里请不要和 == 混了,== 是比较两个变量的值是否相等。

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> id(a)
38884552L
>>> a is b
False
>>> a == b
True</pre>

copy 这个词有两种叫法,一种是根据它的发音音译过来的,叫拷贝;另一种就是标准的翻译,叫复制。

其实单从表面意思来说,copy 就是将某件东西再复制一份,但是在很多编程语言中,比如 Python,C++中,它就不是那么的简单了。

>>> a = 1
>>> b = a
>>> b
1

看到上面的例子,从表面上看我们似乎是得到了两个 1,但是如果你看过我之前写的文章,你应该对一句话有印象,那就是 “变量无类型”, Python 中变量就是一个标签,这里我们有请 id() 闪亮登场,看看它们在内存中的位置。

>>> a = 1
>>> b = a
>>> b
1
>>> id(a)
31096808L
>>> id(b)
31096808L

看出来了吗,id(a) 和 id(b) 相等,所以并没有两个 1,只是一个 1 而已,只不过是在 1 上贴了两张标签,名字是 a 和 b 罢了,这种现象普遍存在于 Python 之中,这种赋值的方式实现了 “假装” 拷贝,真实的情况还是两个变量和同一个对象之间的引用关系。

我们再来看 copy() 方法:

>>> a = {'name':'rocky','like':'python'}
>>> b = a.copy()
>>> b
{'name': 'rocky', 'like': 'python'}
>>> id(a)
31036280L
>>> id(b)
38786728L

咦,果然这次得到的 b 和原来的 a 不同,它是在内存中又开辟了一个空间。那么我们这个时候就来推理了,虽然它们两个是一样的,但是它们在两个不同的内存空间里,那么肯定彼此互不干扰,如果我们去把 b 改了,那么 a 肯定不变。

>>> b['name'] = 'leey'
>>> b
{'name': 'leey', 'like': 'python'}
>>> a
{'name': 'rocky', 'like': 'python'}

结果和我们上面推理的一模一样,所以理解了对象有类型,变量无类型,变量是对象的标签,就能正确推断出 Python 提供的结果。

我们接下来在看一个例子,请你在往下看的时候保证上面的你已经懂了,不然容易晕车。

>>> a = {'name':'rocky','like':'python'}
>>> b = a
>>> b
{'name': 'rocky', 'like': 'python'}
>>> b['name'] = 'leey'
>>> b
{'name': 'leey', 'like': 'python'}
>>> a
{'name': 'leey', 'like': 'python'}

上面的例子看出什么来了吗?修改了 b 对应的字典类型的对象,a 的对象也变了。也就是说, b = a 得到的结果是两个变量引用了同一个对象,但是事情真的这么简单吗?请睁大你的眼睛往下看,重点来了。

>>> first = {'name':'rocky','lanaguage':['python','c++','java']}
>>> second = first.copy()
>>> second
{'name': 'rocky', 'lanaguage': ['python', 'c++', 'java']}
>>> id(first)
31036280L
>>> id(second)
38786728L

在这里的话没有问题,和我们之前说的一样,second 是从 first 拷贝过来的,它们分别引用的是两个对象。

>>> second['lanaguage'].remove('java')
>>> second
{'name': 'rocky', 'lanaguage': ['python', 'c++']}
>>> first
{'name': 'rocky', 'lanaguage': ['python', 'c++']}

发现什么了吗?按理说上述例子中 second 的 lanaguage 对应的是一个列表,我删除这个列表里的值,也只应该改变的是 second 啊,为什么连 first 的也会改,不是应该互不干扰吗?是不是很意外?是我们之前说的不对吗?那我们再试试另一个键:

>>> second['name'] = 'leey'
>>> second
{'name': 'leey', 'lanaguage': ['python', 'c++']}
>>> first
{'name': 'rocky', 'lanaguage': ['python', 'c++']}

前面说的原理是有效的,那这到底是为什么啊,来来来,有请我们的 id() 再次闪亮登场。

>>> id(first['name'])
38829152L
>>> id(second['name'])
38817544L
>>> id(first['lanaguage'])
38754120L
>>> id(second['lanaguage'])
38754120L

其实这里深层次的原因是和 Python 的存储数据的方式有关,这里不做过多的说明(其实是我也不懂。。 在这里,我们只需要知道的是,当 copy() 的时候,列表这类由字符串,数字等复合而成的对象仍然是复制了引用,也就是贴标签,并没有建立一个新的对象,我们把这种拷贝方式叫做浅拷贝(唉呀妈呀,终于把这个概念引出来了。。,言外之意就是并没有解决深层次的问题,再言外之意就是还有能够解决深层次问题的方法。

确实,在 Python 中还有一个深拷贝(deep copy),在使用它之前要引入一个 copy 模块,我们来试一下。

>>> import copy
>>> first = {'name':'rocky','lanaguage':['python','c++','java']}
>>> second = copy.deepcopy(first)
>>> second
{'name': 'rocky', 'lanaguage': ['python', 'c++', 'java']}
>>> second['lanaguage'].remove('java')
>>> second
{'name': 'rocky', 'lanaguage': ['python', 'c++']}
>>> first
{'name': 'rocky', 'lanaguage': ['python', 'c++', 'java']}

用了深拷贝以后,果然就不是引用了。

Python 之详解深拷贝和浅拷贝相关推荐

  1. Python 拓展之详解深拷贝和浅拷贝

    正式开始 首先我在这介绍两个新的小知识,要在下面用到.一个是函数 id() ,另一个是运算符 is.id() 函数就是返回对象的内存地址:is 是比较两个变量的对象引用是否指向同一个对象,在这里请不要 ...

  2. python粘性拓展_Python 拓展之详解深拷贝和浅拷贝

    写在之前 在昨天的文章里 (零基础学习 Python 之字典),写字典的方法的时候留了一个小尾巴,那就是 copy() 方法还没讲.一是因为 copy 这个方法比较特殊,不单单是它表面的意思:二是以为 ...

  3. 详解深拷贝和浅拷贝以及如何深拷贝

    深拷贝和浅拷贝 一.如何区分深拷贝和浅拷贝 二.举例加深理解深拷贝和浅拷贝 三.图文理解 四.哪些方法是浅拷贝,如何进行深拷贝 一.如何区分深拷贝和浅拷贝 内在的区别:浅拷贝就是简单的把指向别人的值的 ...

  4. python 深拷贝_详解python的复制,深拷贝和浅拷贝的区别

    概述 今天主要来看看Python中的浅拷贝和深拷贝内容,这里用一个实例来说明~ 需求: 将一个列表的数据复制到另一个列表中. 思路: 使用列表[:],拿不准可以调用copy模块. 实现方法: #!/u ...

  5. Python数据类型详解03

    原文博客地址: Python数据类型详解03 第一篇Python数据类型详解01中主要介绍了Python中的一些常用的数据类型的基础知识 第二篇Python数据类型详解02文章中, 详细介绍了数字(N ...

  6. python区块链开发_Fabric区块链Python开发详解

    Hyperledger Fabric是最流行的联盟区块链平台.Fabric区块链Python开发详解课程 涵盖Fabric区块链的核心概念.Fabric网络搭建.Node链码开发.Python应用开发 ...

  7. python装饰器setter_第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter...

    上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一.    案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...

  8. 【python】详解类class的继承、__init__初始化、super方法

    原文链接; https://blog.csdn.net/brucewong0516/article/details/79121179?utm_medium=distribute.pc_relevant ...

  9. python与golang_Golang与python线程详解及简单实例

    Golang与python线程详解及简单实例 在GO中,开启15个线程,每个线程把全局变量遍历增加100000次,因此预测结果是 15*100000=1500000. var sum int var ...

最新文章

  1. (转载)人人都会OSGI--实例讲解OSGI开发
  2. nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping
  3. 封神召唤师显示服务器爆满,封神召唤师总是显示无法连接网络
  4. Js~对数组进行分组户数
  5. [译] 原生 JavaScript 值得学习吗?答案是肯定的
  6. kcbzps oracle_Oracle 11g DRCP配置与使用(上)
  7. 用Matlab来备份文件夹
  8. 【干货】JS版汉字与拼音互转终极方案,附简单的JS拼音输入法
  9. OpenCV编译安装
  10. 神经网络入门回顾(感知器、多层感知器)
  11. stage java_Stage 1 - Course 1 - JAVA基础知识
  12. mysql5.5默认引擎_InnoDB 作为默认存储引擎(从mysql-5.5.5开始)
  13. 韵乐x5最佳参数手动_机器学习 4 个常用超参数调试方法!
  14. 虚拟均衡器:Producers Vault Baby Bass for Mac
  15. 测试一下你真的理解数据库左连接了吗?
  16. 谷歌Chrome紧急更新补丁0day漏洞
  17. 服务器维修责合同,2021年服务器维护委托合同样本.doc
  18. 【圣诞快乐】闻到圣诞的气息了,喜欢的节日在慢慢来临~祝大家Merry Christmas。
  19. 我国南北居民收入差距 正在扩大。
  20. uniapp微信小程序授权登录和获取微信绑定的手机号码

热门文章

  1. TCP/IP学习笔记(3)----IP,ARP,RARP协议
  2. ASP.NET之Ajax系列(三)
  3. matlab ode45 初值,为什么设定的初值在ode45里无效?
  4. 帆软报表(FineReport) 的初步学习和使用
  5. 各种集合key,value能否为null
  6. Oracle在plsql上数据类型是nvarchar2(2)表的字段,查询时最后一位不显示
  7. PLSQL的中文乱码显示全是问号
  8. nprogress页面加载进度条
  9. 用winform实现一个B/S代码更新打包工具
  10. 二分图匹配的判断+p1322+二分图最大匹配+tyvj1035