【Python成长之路】快速理解复制、浅拷贝、深拷贝
哈喽大家好,我是鹏哥。
今天想聊聊的主题是 —— 浅拷贝/深拷贝。
~~~上课铃~~~
赤伶HITA - 赤伶
1
写在前面
浅拷贝、深拷贝的知识点,在python笔试和面试的过程中,经常被作为考题来考察应聘者的基本功。比如问你“请简单阐述下浅拷贝、深拷贝之间的差异”,或者给你一个变量分别进行复制、浅拷贝、深拷贝来求新值。
因此,我就简单把自己的理解记录下,希望对部分初学者有所帮助。
2
示例代码
在进行示例代码展示前,我们先理解下什么叫 复制、浅拷贝、深拷贝。
【直接赋值】:其实就是对象的引用(别名)。
【浅拷贝(copy)】:拷贝父对象,不会拷贝对象的内部的子对象。
【深拷贝(deepcopy)】:copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
好吧,反正我开始了解这些时对这 么官方的介绍是看不懂的,完全不知道是 什么意思。
Talk is cheap, Show me the code!
a = 1
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
在进行介绍复制、浅拷贝、深拷贝前,我们还要了解下可变对象(dict/list/set)、不可变对象(int/str/float/tuple)。
【知识点1】可变对象、不可变对象
【可变对象】:当有需要改变对象内部的值的时候,这个对象的id不发生变化。
【不可变对象】:当有需要改变对象内部的值的时候,这个对象的id会发生变化。
a = 1
print(id(a), a)
a = 2
print(id(a), a)
A = [1]
print(id(A), A)
A.append(2)
print(id(A), A)
A = [1,2]
print(id(A),A)
结果:
8791349191504 1
8791349191536 2
34759304 [1]
34759304 [1, 2]
34759368 [1, 2]
从上述代码可以看到,对不可变对象a进行值改变时,a的地址也发生了变化;但对可变对象A进行值改变时,内存地址是不变的,仍然是34759304。(这里注意,A=[1,2]是重新赋值,所以是新地址,可以理解成是A‘,已不再是A)
【知识点2】对不可变对象进行复制、浅/深拷贝
对不可变对象,复制/浅拷贝/深拷贝都是引用原对象的内存地址。
import copy
a = 1
print(id(a), a)print(id(a), a)
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
a = 2
print(id(a), a)
print(id(b), b)
print(id(c), c)
print(id(d), d)
结果:
8791347356496 1 -- 变化前的a
8791347356528 2 -- 变化后的a
8791347356496 1 -- 复制
8791347356496 1 -- 浅拷贝
8791347356496 1 -- 深拷贝
因此,对于不可变对象,如果原对象发生什么变化,复制/浅拷贝/深拷贝都不会跟着变。就像对于一个又没有上进心又穷的小伙子,无论什么女生都不会跟着他过一生,这男的要怎么样就怎么样吧,没人管他。
【知识点3】对可变对象进行复制、浅/深拷贝
import copy
a = [1, 2, [3, 4]]
print(id(a), a)
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
a[1] = 5
a[2].append(6)
a.append(7)
print(id(a), a)
print(id(b), b)
print(id(c), c)
print(id(d), d)
结果:
43241288 [1, 2, [3, 4]] -- 变化前的a
43241288 [1, 5, [3, 4, 6], 7] -- 变化后的a
43241288 [1, 5, [3, 4, 6], 7] -- 复制
43311048 [1, 2, [3, 4, 6]] -- 浅拷贝
43310984 [1, 2, [3, 4]] -- 深拷贝
复制:原对象怎么变,我跟着变。另外,这里在可以发现对于可变对象,a变化前后的内存地址是不变的;就像老人们常说的“嫁鸡随鸡,嫁狗随狗”。
浅拷贝:原对象的外层元素地址变化,内层元素的地址不变。因为浅拷贝是会拷贝原对象的父对象,因此只有外层元素的内存地址发生了变化,因此通过a.append(7)改变外层元素,即外层的列表时,对浅拷贝是不影响的;
那这里你会肯定会问,为什么a[1]=5不变,而a[2].append(6)又发生了变化?因为a[1]是不可变对象,a[2]是可变对象。前面已经提过了,对于不可变对象是不会跟着变的。对于可变对象的子对象变了,浅拷贝是会跟着变的。
就像上面提到的又没有上进心又穷的小伙子,如果只是改变外观(外层元素地址变了)或者变得有钱(穷属性是不可变对象),是不会挽回前女友(浅拷贝)的心,只有改变了上进心(上进心属性是可变对象),前女友才会回心转意而发生变化。
当然如果a[2]是通过a[2]=[3,4,6]来改变的话,浅拷贝是不会跟着变化的。原理已经在第1个知识点里讲过了,这里不再复述。你可以理解成小伙子完全换了颗心脏,都不再是原先那个心脏了。(好吧,这个比方有点牵强。)
深拷贝:原对象的外层/内层元素地址都变化。这个就好理解了,前女友对你彻底死心,无论你怎么变都不要你了。
综上所述,复制相当于是无论什么条件都愿意跟着你结婚的好女孩;浅拷贝相当于有机会回到你身边的前女友,但要看你表现;深拷贝是完全对你死心的前女友。(和面试官可别这么说哈!)
3
补充点
如果对复制/浅拷贝/深拷贝的对象进行改变,那原对象会怎么变呢?
import copy
a = [1, 2, [3, 4]]
print(id(a), a)
# 复制
b = a
# 浅拷贝
c = copy.copy(a)
# 深拷贝
d = copy.deepcopy(a)
b[0] = 9
print(id(a), a)
c[1] = 10
c[2].append(11)
print(id(a), a)
d[2].append(12)
print(id(a), a)
结果:
43241416 [1, 2, [3, 4]] -- 原对象a
43241416 [9, 2, [3, 4]] -- 对复制进行改变后的a
43241416 [9, 2, [3, 4, 11]] --对浅拷贝进行改变后的a
43241416 [9, 2, [3, 4, 11]] -- 对深拷贝进行改变后的a
我想大家应该能理解c[1] = 10为什么不改变原对象,而
c[2].append(11)
能改变原对象的原理吧 ?
4
总结
我觉得,理解复制/浅拷贝/深拷贝的关键还是要看对应外层元素/子层元素的地址有没有变化。地址变了,那就完全是新的对象;如果地址不变,那地址所对应的值变化,也就跟着变化了。另外,还要看原对象是可变对象还是不可变对象。
~~~下课铃~~~
【往期热门文章】:
【Python成长之路】10行代码教你免费观看无广告版的《庆余年》腾讯视频
【Python成长之路】如何用python开发自己的iphone应用程序,并添加至siri指令
【Python成长之路】从 零做网站开发 -- 基于Flask和JQuery,实现表格管理平台
点击下方诗句,可以留言互动喔
四方食事,不过一碗人间烟火。万千得失,不过一段烛光消逝。
【关注“鹏哥贼优秀”公众号,回复“python学习材料”,将会有python基础学习、机器学习、数据挖掘、高级编程教程等100G视频资料,及100+份python相关电子书免费赠送!】
扫描二维码
与鹏哥一起
学python吧!
【Python成长之路】快速理解复制、浅拷贝、深拷贝相关推荐
- 【Python成长之路】如何用python开发自己的iphone应用程序,并添加至siri指令
哈喽大家好,我是鹏哥. 今天想记录的学习主题是 -- 基于pythonista3 app开发自己的iphone应用程序. ~~~上课铃~~~ (由于今天被小伙伴推荐了这首歌,因此就应他的要求,作为此文 ...
- Python成长之路【第九篇】:Python基础之面向对象
一.三大编程范式 正本清源一:有人说,函数式编程就是用函数编程–>错误1 编程范式即编程的方法论,标识一种编程风格 大家学习了基本的Python语法后,大家就可以写Python代码了,然后每个人 ...
- (转)Python成长之路【第九篇】:Python基础之面向对象
一.三大编程范式 正本清源一:有人说,函数式编程就是用函数编程-->错误1 编程范式即编程的方法论,标识一种编程风格 大家学习了基本的Python语法后,大家就可以写Python代码了,然后每个 ...
- 【Python成长之路】破解Boss直聘网站滑块验证
哈喽大家好,我是鹏哥. 今天要记录的内容是 -- 破解Boss直聘网站的滑块验证. -- 上 课 铃-- TuesdayBurak Yeter;Danelle Sandoval - Tuesday 1 ...
- python爬虫入门教程--快速理解HTTP协议(一)
http协议是互联网里面最重要,最基础的协议之一,我们的爬虫需要经常和http协议打交道.下面这篇文章主要给大家介绍了关于python爬虫入门之快速理解HTTP协议的相关资料,文中介绍的非常详细,需要 ...
- 【Python成长之路】Python爬虫 --requests库爬取网站乱码(\xe4\xb8\xb0\xe5\xa)的解决方法【华为云分享】
[写在前面] 在用requests库对自己的CSDN个人博客(https://blog.csdn.net/yuzipeng)进行爬取时,发现乱码报错(\xe4\xb8\xb0\xe5\xaf\x8c\ ...
- 【Python成长之路】Python爬虫 --requests库爬取网站乱码(\xe4\xb8\xb0\xe5\xaf\x8c\xe7\x9)的解决方法
[写在前面] 在用requests库对自己的CSDN个人博客(https://blog.csdn.net/yuzipeng)进行爬取时,发现乱码报错(\xe4\xb8\xb0\xe5\xaf\x8c\ ...
- 【Python成长之路】如何用2行代码将抖音视频设置成我的手机铃声
哈喽大家好,我是鹏哥. 今天想学习记录的内容是 -- 如何用python提取视频中的音频. ~~~上课铃~~~ 1 写在前面 本来按我的性子和精力,一周一般只想写一篇博客:但是今天在刷抖音时,发现有个 ...
- 【Python成长之路】装逼的一行代码:快速共享文件【华为云分享】
[写在前面] 有时候会与同事共享文件,正常人的操作是鼠标右键,点击共享.其实有个装逼的方法,用python的一行代码快速实现基于http服务的共享方式. [效果如下] [示例代码] 在cmd窗口进入想 ...
最新文章
- 【C4D教程】Octane渲染大师班
- ARM中char、short、int、long、float、double数据类型占多少位
- CSDN技术主题月----“深度学习”代码笔记专栏
- POJ2503 UVA10282 Babelfish
- 看视频时,类加载器没太理解,现在再整理下几个要点
- Google Protobuf 使用介绍
- 清北学堂模拟赛d1t1 位运算1(bit)
- 全国医疗机构勒索病毒事件公告:阿里云发布公益行动
- 局域网计算机如何传输文件,局域网如何快速传输文件|同一个局域网传输文件的方法...
- Linux_ppc下软件包安装,LINUX2000PPC安装手册
- 2023年东大学机械专硕考研上岸经验分享
- Gentoo Ebuild 和 Overlay
- php 获取header头信息并显示网址,php 获取远程网址header头信息的方法
- SAP各种BOM详解(包含常用BAPI)
- 阿米洛键盘失灵_改变静电容键盘手感单一限制,阿米洛静电容机械轴V2上手
- 欢迎高校选修云创大数据免费在线直播课!
- 海贼王热血航线正在连接服务器,《航海王热血航线》登录异常解决方法 无法进入怎么解决...
- POJ 1950 Dessert
- 极米、当贝、海信,争抢智能投影蛋糕
- 捷信消费金融十年:巨轮转向,海阔天空
热门文章
- 开始报名丨CCF C³-13@奇安信:透视俄乌网络战 —— 网络空间基础设施面临的安全对抗与制裁博弈...
- 如何在微信公众号正文中添加附件?
- L1-078吉老师的回归
- 013-Vue:前端知识结构概述、基本语法、声明周期
- 「环卫吸粪车」天河区抽化粪池抽泥浆抽污水来了,解决黑臭水体!
- 用php语言说句情话,50句最美情话,套路我都懂,只是舍不得对你用
- 钰泰ETA8113,ETA8120,ETA8121降压转换器,2A/3A电流,OVP保护
- 机器学习项目案例 简单的数字验证码自动识别
- 美团codeM资格赛 优惠券
- 网易笔试题(java 、 c++ 、软件测试等)