引入

  在python程序中,如果我们操作一个变量的值去做运算,而又想在下次调用时,仍使用原来的变量的值去做运算,那么我们我们就需要将这个变量去做备份,这就是本文所要探究的问题。

开始

变量-对象-引用:
  python中全部皆对象,Python中变量是指对象(甚至连type其本身都是对象,type对象)的引用,Python是动态类型,程序运行时候,会根据对象的类型来确认变量到底是什么类型。

我们有时候会见到这样一种情况:

  a = 1

  b = a

这样做不就是把数据copy了一份吗,错,这样做只是在程序中新创建了一个对象b,去引对象a创建是指定的值,也就是说,它们是指向了同一块内存地址,而不是在创建 b = a 时又重新在内存中开辟出一块空间来,所以当一个变量的值被修改,则另一个变量的值也会随之被修改,这样说可能不太理解,来个图示吧:

这个叫做"共享引用",而不是做一个副本(不要犯这样的错哦)。

正题

现在就开始探究一下深浅copy

深浅copy的方法由python内置的一标准库提供(提供的copy方法,适合所有类型对象)
简单点说

  • copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
  • copy.deepcopy 深拷贝 拷贝对象及其子对象

用一个简单的例子来说明一下

>>> import copy
>>> a = [1,2,3,['a','b','c']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)

a是一个列表,表中的a[3]也是一个列表(也就是一个内部的子对象),b是对a列表的又一个引用,所有a,b是完全相同的,我们可以通过id(a)来验证。

>>> id(a)
60356208
>>> id(b)
60356208
>>> id(c)
63132896
>>> id(d)
63133256

a 和 b的相同也证实了前面所说的共享引用;

深浅copy的区别:

浅copy

>>> import copy
>>> a = [1,2,3,['a','b','c']] #a具有两级对象的列表
>>> b = copy.copy(a) #创建变量b,使其浅copy a的值
>>> b
[1, 2, 3, ['a', 'b', 'c']]
>>> a[1] = "two" #当a的父对象修改之后而b的父对象不会被修改
>>> a
[1, 'two', 3, ['a', 'b', 'c']]
>>> b
[1, 2, 3, ['a', 'b', 'c']]
>>> a[3][0] = 'A' #当a的子对象被修改之后b的子对象也会随之修改
>>> a
[1, 'two', 3, ['A', 'b', 'c']]
>>> b
[1, 2, 3, ['A', 'b', 'c']]

深copy

>>> import copy
>>> a = [1,2,3,['a','b','c']] #a具有两级对象的列表
>>> b = copy.deepcopy(a) #创建变量b,使其深copy a的值
>>> b
[1, 2, 3, ['a', 'b', 'c']]
>>> a[1] = "two" #当a的父对象修改之后而b的父对象不会被修改
>>> a
[1, 'two', 3, ['a', 'b', 'c']]
>>> b
[1, 2, 3, ['a', 'b', 'c']]
>>> a[3][0] = 'A' #当a的子对象被修改之后b的子对象仍不会随之修改
>>> a
[1, 'two', 3, ['A', 'b', 'c']]
>>> b
[1, 2, 3, ['a', 'b', 'c']]

浅拷贝是指拷贝的只是原对象元素的引用,换句话说,浅拷贝产生的对象本身是新的,但是它的内容不是新的,只是对原对象的一个引用

>>> aList=[[1, 2], 3, 4]
>>> bList = aList[:] #利用切片完成一次浅拷贝
>>> id(aList)
3084416588L
>>> id(bList)
3084418156L
>>> aList[0][0] = 5
>>> aList
[[5, 2], 3, 4]
>>> bList
[[5, 2], 3, 4]

但是有点需要特别提醒的,如果对象本身是不可变的,那么浅拷贝时也会产生两个值

>>> aList = [1, 2]
>>> bList = aList[:]
>>> bList
[1, 2]
>>> aList
[1, 2]
>>> aList[1]=111
>>> aList
[1, 111]
>>> bList
[1, 2]

为什么bList的第二个元素没有变成111呢?因为数字在python中是不可变类型!!

在这顺便回顾下Python标准类型的分类:

  • 可变类型: 列表,字典
  • 不可变类型:数字,字符串,元组

理解了浅拷贝,深拷贝是什么自然就很清楚了。
python中有一个模块copy,deepcopy函数用于深拷贝,copy函数用于浅拷贝。
最后,对象的赋值是深拷贝还是浅拷贝?
对象赋值实际上是简单的对象引用

>>> a = 1
>>> id(a)
135720760
>>> b = a
>>> id(b)
135720760

a和b完全是一回事。

python深浅copy探究的更多相关文章

  1. Python 深浅copy 和文件操作

    深浅copy 1,先看赋值运算. l1 = [1,2,3,['barry','alex']] l2 = l1 l1[0] = 111 print(l1) # [111, 2, 3, ['barry', ...

  2. python深浅copy

    预备知识一——python的变量及其存储 在详细的了解python中赋值.copy和deepcopy之前,了解一下python内存中变量的存储情况. 在高级语言中,变量是对内存及其地址的抽象.对于py ...

  3. python深浅copy和赋值

    Python直接赋值,浅copy和深copy的比较 基于引用和对象(python引用和对象分离) 总结: 直接赋值:a = b -->a,b两个引用指向相同的对象 浅copy:a为b的copy ...

  4. Python——深浅Copy

    1. 赋值 赋值:指向同一块内存地址,所以同时改变 l1 = [1,2,3] l2 = l1 l1.append('a') print(l1,l2) # [1, 2, 3, 'a'] [1, 2, 3 ...

  5. python 深浅copy的例子

    1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.2. copy.deepcopy 深拷贝 拷贝对象及其子对象一个很好的例子:import copya = [1, 2, 3, ...

  6. python 深浅copy总结

    总结: ''' 总结:假设l1为原数据,l2为deepcopy后的数据: 1.浅copy,只能改变第一层的内存地址(不可变数据类型除外). 2.深copy,能够改变第一层和第二层的内存地址(不可变数据 ...

  7. 番外:深浅copy

    进击のpython 深浅copy copy是什么意思? 复制 (又学一个单词!开不开森) 那啥叫复制呢? 百度百科上给的解释是:仿原样品制造 我们曾经有过这样的印象 a = "zhangsa ...

  8. python基础3(元祖、字典、深浅copy、集合、文件处理)

    本次内容: 元祖 字典 浅copy和深copy 集合 文件处理 1.1元祖 元祖(tuple)与列表类似,不同之处在于元祖的元素不能修改,元祖使用小括号(),列表使用方括号[].元祖创建很简单,只需要 ...

  9. python学习笔记三 深浅copy,扩展数据类型(基础篇)

    深浅copy以及赋值 对于字符串和数字而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址. import copy n1 = #n1 = 'hahahaha' #赋值n2 = n1#浅co ...

随机推荐

  1. docker被入侵后.............

    服务器上线后,怎么发现总有个 xmrig 的容器在跑,删了还出来 那么恭喜你!!你的服务器已经被入侵了!! $ docker ps IMAGE               COMMAND       ...

  2. rook 入门理解

    参考:https://my.oschina.net/u/2306127/blog/1830356?from=timeline 1.Rook通过一个操作器(operator)完成后续操作,只需要定义需要 ...

  3. properties中的编码如何生成:例如\u7AD9\u70B9这种。

    在eclipse中的properties中的一种编码,例如\u7AD9\u70B9,是如何自动生成的. 这种编码方式当你要增加某个字段的时候,也要相应的添加这种编码方式下的格式,具体方法如下:

  4. LOJ2538 PKUWC2018 Slay the Spire DP

    传送门 不想放题面了,咕咕咕咕咕 这个期望明明是用来吓人的,其实要算的就是所有方案的最多伤害的和. 首先可以知道的是,能出强化牌就出强化牌(当然最后要留一张攻击牌出出去),且数字尽量大 所以说在强化牌 ...

  5. Java 面试题 队列

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构 Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Deque接 口.   Q ...

  6. Linux/CentOS下安装MySql RPM Bundle

    一.下载对应的版本的MySql安装文件 1.下载路径 https://dev.mysql.com/downloads/mysql/ 2.选择对应的Linux版本和x86/x64位的安装文件 查看Lin ...

  7. Spring boot多模块(moudle)中的一个注入错误(Unable to start embedded container; nested exception is org)

    org.springframework.context.ApplicationContextException: Unable to start embedded container; nested ...

  8. docker部署rabbitMQ

    获取rabbit镜像: docker pull rabbitmq:management 创建并运行容器: docker run -d --hostname my-rabbit --name rabbi ...

  9. [UWP 自定义控件]了解模板化控件(1):基础知识

    1.概述 UWP允许开发者通过两种方式创建自定义的控件:UserControl和TemplatedControl(模板化控件).这个主题主要讲述如何创建和理解模板化控件,目标是能理解模板化控件常见的知 ...

  10. Ubuntu16.04下安装QQ的完整操作记录(经验证可用)

    本机安装了Ubuntu16.04系统,用于日常运维办公.打算在Ubuntu上安装QQ,如下操作记录也使用于Ubuntu18.04: 1)先下载特制的QQ程序包(其实就是基于Wine容器做了一些封装,程 ...