Python---copy()、deepcopy()与赋值的区别
copy()与deepcopy()之间的主要区别是python对数据的存储方式。
首先直接上结论:
—–深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。
—–而等于赋值,并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。
—–而浅复制要分两种情况进行讨论:
1)当浅复制的值是不可变对象(数值,字符串,元组)时和“等于赋值”的情况一样,对象的id值与浅复制原来的值相同。
2)当浅复制的值是可变对象(列表和元组)时会产生一个“不是那么独立的对象”存在。有两种情况:
第一种情况:复制的 对象中无 复杂 子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。
第二种情况:复制的对象中有 复杂 子对象 (例如列表中的一个子元素是一个列表),如果不改变其中复杂子对象,浅复制的值改变并不会影响原来的值。 但是改变原来的值 中的复杂子对象的值 会影响浅复制的值。
对于简单的 object,例如不可变对象(数值,字符串,元组),用 shallow copy 和 deep copy 没区别
复杂的 object, 如 list 中套着 list 的情况,shallow copy 中的 子list,并未从原 object 真的「独立」出来。也就是说,如果你改变原 object 的子 list 中的一个元素,你的 copy 就会跟着一起变。这跟我们直觉上对「复制」的理解不同。
当浅复制的值是不可变对象(数值,字符串,元组)时,代码如下:
>>> a="1234567">>> b=a>>> id(a)4367619440>>> id(b)4367619440>>> c=copy.copy(a)>>> id(c)4367619440>>> d=copy.deepcopy(a)>>> id(d)4367619440
当浅复制的值是可变对象(列表,字典)时,改变的值不是 复杂子对象 代码如下:
>>> l1=[1,2,3]>>> l2=l1>>> l3=copy.copy(l1)>>> id(l1)4367654664>>> id(l2)4367654664>>> id(l3)4367628616>>> l1.append(55)>>> print(l1)[1, 2, 3, 55]>>> print(l3)[1, 2, 3]
当浅复制的值是可变对象(列表,字典)时,改变的值是 复杂子对象 代码如下:
>>> import copy>>> list1=[1,2,['a','b']]>>> list2=list1>>> list3=copy.copy(list2)>>> list4=copy.deepcopy(list3)>>> id(list1)4338414656>>> id(list2)4338414656>>> id(list3)4338415016>>> id(list4)4338414368>>> list1[2].append('a')>>> id(list1)4338414656>>> print list1[1, 2, ['a', 'b', 'a']]>>> print list3[1, 2, ['a', 'b', 'a']]>>> print list4[1, 2, ['a', 'b']]>>> list1.append(33)>>> id(list1)4338414656>>> id(list3)4338415016>>> print list1[1, 2, ['a', 'b', 'a'], 33]>>> print list3[1, 2, ['a', 'b', 'a']]
代码说明:当改变 复杂子对象中的元素时,浅复制值发生了变化; 当改变的值不是复杂子对象,浅复制的值没有发生变化。因为 浅复制 ,复杂子对象的保存方式是 作为 引用 方式存储的,所以修改 浅复制的值 和原来的值都可以 改变 复杂子对象的值。
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 == cop2True>>> cop1 is cop2False#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概念图如下:
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了。即我们寻常意义上的复制。
参考文章 http://iaman.actor/blog/2016/04/17/copy-in-python
Python---copy()、deepcopy()与赋值的区别相关推荐
- copy与deepcopy、赋值的区别
copy()与deepcopy()之间的主要区别是python对数据的存储方式. 首先直接上结论: :深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变原有被复制对象不会对已经复制 ...
- python copy.deepcopy()深入解读
copy.deepcopy()的用法是将某一个变量的值赋值给另一个变量(此时两个变量地址不同),因为地址不同,所以可以防止变量间相互干扰. 大家可以猜猜下面代码第四行输出什么值 例1. a = [1, ...
- Python中copy,deepcopy,浅拷贝(“=”)和深拷贝(“copy.deepcopy()”)
python中对于对象的拷贝分为浅拷贝(copy)和深拷贝(deepcopy)两种方式.其中浅拷贝由"="完成.而深拷贝由copy模块中deepcopy()函数担任. 浅拷贝和深拷 ...
- 浅拷贝copy(“=”)和深拷贝(“copy.deepcopy()”)
python中对于对象的拷贝分为浅拷贝(copy)和深拷贝(deepcopy)两种方式. 其中浅拷贝由"="完成.而深拷贝由copy模块中deepcopy()函数担任. 浅拷贝和深 ...
- Python copy()与deepcopy()方法的区别
copy()与deepcopy()之间的区分必须要涉及到python对于数据的存储方式. 首先直接上结论: 我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以改变 ...
- Python 玩转数据 5 - 图解 Python 赋值,浅拷贝 copy.copy() 和 深拷贝 copy.deepcopy() 原理
引言 上面文章有介绍 Python 动态类型 共享引用等相关知识,有这个基础,我们来深入研究一下 Python 赋值,拷贝的原理,有涉及到可变类型和不可变类型的不同处理.更多 Pyton 进阶系列文章 ...
- python:copy()和deepcopy()区别
1.对象的赋值 都是进行对象引用(内存地址)传递,即'' b is a'' ,a 变 b 也变 2.copy.copy(x):浅拷贝 会创建一个新的对象,即 "b is not a" ...
- python copy()和deepcopy()解释(import copy)
对于简单的 object,用 shallow copy 和 deep copy 没区别 复杂的 object, 如 list 中套着 list 的情况,shallow copy 中的 子list,并未 ...
- Python 之 = [:] copy deepcopy
写在前面 已经见多很多这样的Blog,为什么还想自己写呢?原因很简单,每当学到一个知识时候,尝试着对自己或者别人讲解这个知识点,当别人能听懂的时候,就算是真的理解了. 重要部分 首先,要分清楚id() ...
最新文章
- centos7 install 安装mysql
- 为什么java退出全屏_Java全屏模式与退出全屏:
- ECSHOP让产品浏览历史按照先后进行排序
- 098 Validate Binary Search Tree 验证二叉搜索树
- tomcat常见错误处理
- 64位ubuntu kylin 16.04下tiny4412开发环境搭建
- python回到本次循环开头_Python中,当一个while循环判断为false,结束这个循环的时候,怎么进入到下一个循环中?...
- 设计代码说明什么是多态性?如何实现多态?(代码中要写注释解释)_狗屎一样的代码!快,重构我...
- 【汇编语言】指令寻址
- HTML生成Word文档,可自定义Word文档页眉、页脚、分页。
- python嗅探器_Python中的包嗅探器
- ROCKCHIP UART开发指南
- TAS5760M-Q1 放大器内部时钟误差被锁存问题
- MatLab实现的ftt大数乘法
- SIMCom芯片关于GPS定位信息的的解析(AT+CGNSINF)
- Cortex-M3 VS ARM7
- @Transactional使用
- python Pygame的具体使用讲解
- CentOS7安装MongoDB及基础操作
- 【游戏设计】从星露谷物语中学习游戏制作
热门文章
- bzoj 1055: [HAOI2008]玩具取名(区间DP)
- [python] 将一个序列的排序方式扩展到其他序列
- airflow时区问题
- linux-网络数据包抓取-tcpdump
- python机器学习库sklearn——Lasso回归(L1正则化)
- 安卓Intent的Action中的常值变量:窗口action常量(android.intent.action.+xxx),广播action常量(android.intent.action.+xxx)
- java获取响应网页源代码
- java图片亮度调整
- HWDB数据集gnt格式转为png格式
- 贺利坚老师汇编课程54笔记:PF奇偶标志PARITY FLAG