对于简单的 object,用 shallow copy 和 deep copy 没区别

复杂的 object, 如 list 中套着 list 的情况,shallow copy 中的 子list,并未从原 object 真的「独立」出来。也就是说,如果你改变原 object 的子 list 中的一个元素,你的 copy 就会跟着一起变。这跟我们直觉上对「复制」的理解不同。

看不懂文字没关系我们来看代码:

>>> import copy
>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)
>>> cop1 == cop2
True
>>> cop1 is cop2
False
#cop1 和 cop2 看上去相同,但已不再是同一个object
>>> origin[2][0] = "hey!"
>>> origin
[1, 2, ['hey!', 4]]
>>> cop1
[1, 2, ['hey!', 4]]
>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2

可以看到 cop1,也就是 shallow copy 跟着 origin 改变了。而 cop2 ,也就是 deep copy 并没有变。

似乎 deep copy 更加符合我们对「复制」的直觉定义: 一旦复制出来了,就应该是独立的了。如果我们想要的是一个字面意义的「copy」,那就直接用 deep_copy 即可。

那么为什么会有 shallow copy 这样的「假」 copy 存在呢? 这就是有意思的地方了。

python的数据存储方式
Python 存储变量的方法跟其他 OOP 语言不同。它与其说是把值赋给变量,不如说是给变量建立了一个到具体值的 reference。

当在 Python 中 a = something 应该理解为给 something 贴上了一个标签 a。当再赋值给 a 的时候,就好象把 a 这个标签从原来的 something 上拿下来,贴到其他对象上,建立新的 reference。 这就解释了一些 Python 中可能遇到的诡异情况:

>> a = [1, 2, 3]
>>> b = a
>>> a = [4, 5, 6] //赋新的值给 a
>>> a
[4, 5, 6]
>>> b
[1, 2, 3]
# a 的值改变后,b 并没有随着 a 变>>> a = [1, 2, 3]
>>> b = a
>>> a[0], a[1], a[2] = 4, 5, 6 //改变原来 list 中的元素
>>> a
[4, 5, 6]
>>> b
[4, 5, 6]
# a 的值改变后,b 随着 a 变了

上面两段代码中,a 的值都发生了变化。区别在于,第一段代码中是直接赋给了 a 新的值(从 [1, 2, 3] 变为 [4, 5, 6]);而第二段则是把 list 中每个元素分别改变。

而对 b 的影响则是不同的,一个没有让 b 的值发生改变,另一个变了。怎么用上边的道理来解释这个诡异的不同呢?

首次把 [1, 2, 3] 看成一个物品。a = [1, 2, 3] 就相当于给这个物品上贴上 a 这个标签。而 b = a 就是给这个物品又贴上了一个 b 的标签。

第一种情况:

a = [4, 5, 6] 就相当于把 a 标签从 [1 ,2, 3] 上撕下来,贴到了 [4, 5, 6] 上。

在这个过程中,[1, 2, 3] 这个物品并没有消失。 b 自始至终都好好的贴在 [1, 2, 3] 上,既然这个 reference 也没有改变过。 b 的值自然不变。

第二种情况:

a[0], a[1], a[2] = 4, 5, 6 则是直接改变了 [1, 2, 3] 这个物品本身。把它内部的每一部分都重新改装了一下。内部改装完毕后,[1, 2, 3] 本身变成了 [4, 5, 6]。

而在此过程当中,a 和 b 都没有动,他们还贴在那个物品上。因此自然 a b 的值都变成了 [4, 5, 6]。

搞明白这个之后就要问了,对于一个复杂对象的浅copy,在copy的时候到底发生了什么?
再看一段代码:

>>> import copy
>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)
>>> cop1 == cop2
True
>>> cop1 is cop2
False
#cop1 和 cop2 看上去相同,但已不再是同一个object
>>> origin[2][0] = "hey!"
>>> origin
[1, 2, ['hey!', 4]]
>>> cop1
[1, 2, ['hey!', 4]]
>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2

学过docker的人应该对镜像这个概念不陌生,我们可以把镜像的概念套用在copy上面。

概念图如下:

copy对于一个复杂对象的子对象并不会完全复制,什么是复杂对象的子对象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是复杂对象的子对象。对于子对象,python会把它当作一个公共镜像存储起来,所有对他的复制都被当成一个引用,所以说当其中一个引用将镜像改变了之后另一个引用使用镜像的时候镜像已经被改变了。

所以说看这里的origin[2],也就是 [3, 4] 这个 list。根据 shallow copy 的定义,在 cop1[2] 指向的是同一个 list [3, 4]。那么,如果这里我们改变了这个 list,就会导致 origin 和 cop1 同时改变。这就是为什么上边 origin[2][0] = “hey!” 之后,cop1 也随之变成了 [1, 2, [‘hey!’, 4]]。

而deepcopy概念图如下:

deepcopy的时候会将复杂对象的每一层复制一个单独的个体出来。
这时候的 origin[2] 和 cop2[2] 虽然值都等于 [3, 4],但已经不是同一个 list了。即我们寻常意义上的复制。

python copy()和deepcopy()解释(import copy)相关推荐

  1. python copy()和deepcopy()解释(浅拷贝、深拷贝)

    对于简单的 object,用 shallow copy 和 deep copy 没区别 复杂的 object, 如 list 中套着 list 的情况,shallow copy 中的 子list,并未 ...

  2. Python:赋值,copy和deepcopy区别

    参考:Python赋值,copy,deepcopy区别 结论 copy()与deepcopy()之间的主要区别是python对数据的存储方式. python2中,需要import copy模块.pyt ...

  3. 2020-09-18 python中copy()和deepcopy()详解

    首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立的对 ...

  4. python中copy()和deepcopy()详解

    参考文章 http://iaman.actor/blog/2016/04/17/copy-in-python **首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独 ...

  5. Python copy()与deepcopy()方法的区别

    copy()与deepcopy()之间的区分必须要涉及到python对于数据的存储方式. 首先直接上结论: 我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变 ...

  6. Python中copy()和deepcopy()的区别

    同样是copy,二者有什么不同呢今天我们就一探究竟!!! 关于copy()和deepcopy()的第一篇博客 初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从 ...

  7. python中deepcopy函数_python中copy()和deepcopy()详解

    **首先直接上结论: -–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制出来的新对象产生影响. -–而浅复制并不会产生一个独立 ...

  8. Python基础教程:copy()和deepcopy()

    在处理列表和字典时,尽管传递引用常常是最方便的方法,但如果函数修改了传入的列表或字典,你可能不希望这些变动影响原来的列表或字典.要做到这一点,Python提供了名为copy的模块,其中包含copy() ...

  9. Python天天美味(22) - 拷贝对象(深拷贝deepcopy与浅拷贝copy)

    Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deep ...

最新文章

  1. 掌握图神经网络GNN基本,看这篇文章就够了
  2. 前端进阶之路 0.1+0.2 !== 0.3?
  3. substring 在C#,Javascript,SQL 中index开始值
  4. 你确定自己不是那只猫吗
  5. sentinel卫星_IKONOS卫星 遥感影像解译数据 波段
  6. SAP License:SAP权限对象文集
  7. CPU究竟是如何执行任务的?
  8. Windows Server 2008远程桌面多用户登陆的配置方法
  9. 国外大神整理的 2019 年 Java 权威开发路线图,Java大神养成记
  10. UltraISO/Nero/Daemon Tools
  11. B - Gary's Calculator
  12. Python自动化 requests 库:发送 form-data 格式的 http 请求
  13. 削峰填谷,你只知道消息队列?
  14. pageadmin CMS网站制作教程:栏目单页内容如何修改
  15. K - 链表的有序集合_Java
  16. View 事件分发机制
  17. 计算机学院嘉年华标题,“芯动盛夏 AI创南航” 计算机学院举办第八届计算机嘉年华...
  18. Python的numpy库中rand(),randn(),randint(),random_integers()等random系函数的使用
  19. 微信小程序 背景音乐BackgroundAudioManager
  20. 纯css打造超能陆战队--大白

热门文章

  1. 推荐一个在线全自动智能图片背景扣除工具,效果杠杠的
  2. 计算机采用二进制形式的表示,计算机部信息的表示及存储往往采用二进制形式,采用这种形式的最主要原因是...
  3. 【ES6(2015)】Reflect
  4. ThinkPHP6项目基操(9.架构分层)
  5. python不等于_Python小课堂|注释+运算符
  6. g++ 安装python_卧槽,又一款Python神器
  7. Java笔记-JdbcTemplate批量执行insert及update
  8. 大三软件工程小项目-小技术集合-socket环境搭建
  9. 汇编:用户登录以及简单数据加密
  10. 联发科有没有高端处理器_2021年华为将成为联发科最大客户?麒麟或将“灭亡?”...