直接赋值: 对象的引用,也就是给对象起别名

浅拷贝: 拷贝父对象,但是不会拷贝对象的内部的子对象。

深拷贝: 拷贝父对象. 以及其内部的子对象

在之前的文章中,提到可变对象和不可变对象,接下来也是以这两者的区别进行展开

直接赋值

对于可变对象和不可变对象,将一个变量直接赋值给另外一个变量,两者 id 值一致,其实本质上是将变量量绑定到对象的过程.

>>> a=1
>>> b=a
>>> id(a) == id(b)
True
>>> c="string"
>>> d=c
>>> id(c) == id(d)
True
>>> e=[1,2,3]
>>> f=e
>>> id(e)==id(f)
True

关于修改新变量的值,对原有变量会产生的影响,在可变对象和不可变对象 中也做了讲述,这里通过几个例子,重新温习一下

不可变对象

>>> x=1
>>> y=x
>>> id(x)==id(y)
True
>>> id(1)==id(y)
True
>>>>>> id(x)
1500143776
>>> y=y+1
>>> y
2
>>> x
1
>>> id(x)==id(y)
False
>>> id(y)
1500143808
>>> id(x)
1500143776

对于不可变对象,修改赋值后的新变量,不会对原有变量造成任何影响.为什么出现这种现象呢?因为不可变对象一旦创建之后就不允许被改变.后面对 y 进行的操作,其实是重新创建一个对象并绑定的结果:

可变对象

>>> m=[1,2,3]
>>> n=m
>>> id(n)==id(m)
True
>>> id(m)
1772066764488
>>> id(n[0])
1772066764656
>>> n[0]=4
>>> n
[4, 2, 3]
>>> m
[4, 2, 3]
>>> id(n)==id(m)
True
>>> id(m)
1772066764488

对于可变对象,修改赋值后的变量,会对原有的变量造成影响,会导致其 value 值的改变,但是其 id 值保持不变

从上图不难看出,这个时候的 id(n[0]) 的值,和未修改前的 id值应该不一样,可以输出看一下

>>>id(n[0])
1772066764752 # 最初没有修改前是 1772066764656

n[0] 修改前后为什么 id 值出现改变呢? 首先需要明确一点 n[0] 绑定的是一个不可变对象,在文章的最初提到,不可变对象一旦创建就不允许修改.显然对 n[0] 进行修改,不能在绑定对象的内存上进行修改,那如何实现重新赋值呢?只能创建一个新的对象 4 ,然后将 n[0] 绑定到新的对象

浅拷贝和深拷贝

先看一下官方文档的定义

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or

class instances).

A shallow copy constructs a new compound object and then (to the

extent possible) inserts the same objects into it that the

original contains.

A deep copy constructs a new compound object and then, recursively,inserts copies into it of the objects found in the original.

从文档中不难看出,上面提到深拷贝和浅拷贝两者区别在于在复合对象,那接下来也只讨论复合对象.

浅拷贝

注意到官方文档也提到对浅拷贝和深拷贝的定义,从上文中不难看出,浅拷贝构建一个复合对象,然后将原有复合对象包含的对象插入到新的复合对象中

从上图不难看出,浅拷贝后,新复合对象包含的对象(可变或者不可变)的 id 值和原有对象包含的对象的 id 值相同

看一下具体例子:

>>> import copy
>>> a=[1,2,[3,4]]
>>> b=copy.copy(a)
>>> id(b[0])==id(a[0])
True
>>> id(b[2])==id(a[2])
True
>>> id(b[2][0])==id(a[2][0])
True

现在让我们试着修改一下浅拷贝后的 b 的值,在修改前,可以先思考一下,如果修改 b[0] 可能会发生什么?

由于 b[0] = 1,很显然 1 属于不可变对象,那么根据对不可变变量修改的规则,则 b[0] 会绑定到新的变量上,而 a[0] 的由于没有修改,则保持不变,真的是这样吗?让我们验证一下

>>> b[0]=5
>>> b
[5, 2, [3, 4]]
>>> a
[1, 2, [3, 4]]

接下来我们要尝试修改一下 b[2],由于 b[2] 绑定的对象是 list,属于可变对象,按照上面说的可变对象修改的规则,则修改后的 b[2] 的 id 值保持不变,但是其 value 值会发生改变. 同样的让我们通过例子验证一下

>>> id(b[2])
4300618568
>>> b[2][0]=6
>>> id(b[2])
4300618568
>>> b
[5, 2, [6, 4]]
>>> a
[1, 2, [6, 4]]

由于 b[2] 和 a[2] 绑定同一个可变对象,很显然对 b[2] 的修改同样会映射到 a[2] 上

深拷贝

深拷贝构建一个复合对象,然后递归的将原有复合包含的对象的副本插入到新的复合对象中

若上图所示,深拷贝后,新的复合对象包含的对象,若对象为不可变对象,则 id 值保持不变,若对象为可变对象,则 id 值发生改变

看一个例子:

>>> import copy
>>> a=[1,2,[3,4]]
>>> b=copy.deepcopy(a)
>>> id(b[0])==id(a[0])
True
>>> id(b[2])==id(a[0])
False
>>> id(b[2][0])==id(a[2][0])
True

接下来让我们修改一下变量 b,这里就不在修改不可变对象 b[0] 和 b[1] 了,因为结果很明显,对 a 不会产生任何影响,我们来修改 b[2],那么修改 b[2] 会对 a[2] 产生影响吗?很明显答案是不会,因为深拷贝就相当于克隆出了一个全新的个体,两者不再有任何关系

>>> b[2][0]=5
>>> b
[1, 2, [5, 4]]
>>> a
[1, 2, [3, 4]]

【Python】直接赋值,深拷贝和浅拷贝的更多相关文章

  1. **Python中的深拷贝和浅拷贝详解

    Python中的深拷贝和浅拷贝详解   这篇文章主要介绍了Python中的深拷贝和浅拷贝详解,本文讲解了变量-对象-引用.可变对象-不可变对象.拷贝等内容.   要说清楚Python中的深浅拷贝,需要 ...

  2. python中的深拷贝与浅拷贝

    深拷贝和浅拷贝 浅拷贝的时候,修改原来的对象,浅拷贝的对象不会发生改变. 1.对象的赋值 对象的赋值实际上是对象之间的引用:当创建一个对象,然后将这个对象赋值给另外一个变量的时候,python并没有拷 ...

  3. 浅谈python 复制(深拷贝,浅拷贝)

    博客参考:点击这里 python中对象的复制以及浅拷贝,深拷贝是存在差异的,这儿我们主要以可变变量来演示,不可变变量则不存在赋值/拷贝上的问题(下文会有解释),具体差异如下文所示 1.赋值: a=[1 ...

  4. python中的深拷贝和浅拷贝

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

  5. 001 说说Python中的深拷贝和浅拷贝

    在Python编程中忽略深拷贝和浅拷贝可能会造成未知的风险. 比如我们打算保存一份原始对象的副本作为上一状态的记录,此后修改原始对象数据时,若是副本对象的数据也发生改变,那么这就是一个严重的错误. 注 ...

  6. Python 对象的深拷贝与浅拷贝 -- (转)

    本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...

  7. Python list的深拷贝和浅拷贝

    深拷贝和浅拷贝 列表存储数据,列表拷贝就是数据备份 浅拷贝 优点:占用内存较少 缺点:修改深层数据,会影响原数据 深拷贝 优点:修改数据,互不影响 缺点:占用内存较大 ""&quo ...

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

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

  9. python中的深拷贝和浅拷贝理解

    在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用.以下分两个思路来分别理解浅拷贝和深拷贝: 利用切 ...

随机推荐

  1. springmvc使用<mvc:default-servlet-handler/>导致的handler失效

    使用springmvc时,会在web.xml中配置对所有请求进行拦截 <!-- 配置springmvc拦截的请求--> <servlet-mapping> <servle ...

  2. [computer graphics]世界坐标系->相机坐标系详细推导

    基变换 理论部分 在n维的线性空间中,任意n个线性无关的向量都可以作为线性空间的基,即空间基不唯一.对于不同的基,同一个向量的坐标一般是不同的.因为在计算机图形学中,主要研究三维的空间,所以可以简化问 ...

  3. ping外网:unknown host www.baidu.comc排查

    ping 百度出现:(ping www.baidu.com) "ping: unknown host www.baidu.com"    1.ping 网关确定是否连接上路由器,并 ...

  4. App接口设计之token的php实现

    为了保证移动端和服务端数据传输相对安全,需要对接口进行加密传输. 一.ttoken的设计目的:  因为APP端没有和PC端一样的session机制,所以无法判断用户是否登陆,以及无法保持用户状态,所以 ...

  5. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现. 业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口. 实现功能:写一个拦 ...

  6. Redis学习笔记(二十一) 事务

    文章开始啰嗦两句,写到这里共21篇关于redis的琐碎知识,没有过多的写编程过程中redis的应用,着重写的是redis命令.客户端.服务器以及生产环境搭建用到的主从.哨兵.集群实现原理,如果你真的能 ...

  7. 一个简单的CSS登录页

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. vue父路由高亮不显示

    vue父路由高亮不显示 首页和考试中心作为父路由,点击时发现不高亮,是因为路由配置有问题 因为首页和考试中心已经重定向到homepage和tpersonal-data这两个路由,当点击首页和考试中心的 ...

  9. Java技术开发标准JSR介绍

    JSR我们需要先提及JCP(Java Community Process SM(JCP SM)).JCP是为Java技术开发标准技术规范的机制.任何人都可以注册并参与审阅和提供Java规范请求(JSR ...

  10. JAVA 经典算法 40 例

    [程序 1] 题目:古典问题:有一对兔子,从出生后第 3 个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔子的规律为数列 ...