Python中你必须要知道的深拷贝和浅拷贝(对象赋值操作)

鳄鱼君Ba

发表文章数:518

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python教程 » Python中你必须要知道的深拷贝和浅拷贝(对象赋值操作)

Python中的深拷贝浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样,也就是内存地址的复制还是值的复制的区别。那么你需要更深入的知道:

什么是赋值?

Python中,所谓的赋值实际上就是对象引用的传递而已,当创建一个对象的时候,再赋值给另外一个变量的时候,并不是赋值给另一个变量。而是把这个变量在地址空间的id地址值传递给另一个变量,简单的说就是拷贝了这个对象的引用。

什么是可变对象,什么是不可变对象?

  • 可变对象:一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值
  • 不可变对象:一个对象所指向的地址上值是不能修改的,如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象指向的值复制出来一份,然后做了修改后存到另一个地址上了,但是可变对象就不会做这样的动作,而是直接在对象所指的地址上把值给改变了,而这个对象依然指向这个地址。

深拷贝和浅拷贝需要注意的地方就是可变元素的拷贝:

浅拷贝相对于深拷贝最根本的区别:浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样。

Python中可以使用id()内置函数,来查看变量的内存地址,在Python自带的交互终端,我们可以这样尝试:

import copy
a=[1,2,3,4,5,['a','b']]#原始对象
b=a#赋值,传对象

c=copy.copy(a)#对象拷贝,浅拷贝
d=copy.deepcopy(a)#对象拷贝,深拷贝
print ("a=",a,"    id(a)=",id(a),"id(a[5])=",id(a[5]))
print ("b=",b,"    id(b)=",id(b),"id(b[5])=",id(b[5]))
print ("c=",c,"    id(c)=",id(c),"id(c[5])=",id(c[5]))
print ("d=",d,"    id(d)=",id(d),"id(d[5])=",id(d[5]))
print ("*"*70)

a.append(6)#修改对象a
a[5].append('c')#修改对象a中的['a','b']数组对象
print ("a=",a,"    id(a)=",id(a),"id(a[5])=",id(a[5]))
print ("b=",b,"    id(b)=",id(b),"id(b[5])=",id(b[5]))
print ("c=",c,"       id(c)=",id(c),"id(c[5])=",id(c[5]))
print ("d=",d,"            id(d)=",id(d),"id(d[5])=",id(d[5]))


# a= [1, 2, 3, 4, 5, ['a', 'b']]     id(a)= 38607048 id(a[5])= 39219400
# b= [1, 2, 3, 4, 5, ['a', 'b']]     id(b)= 38607048 id(b[5])= 39219400
# c= [1, 2, 3, 4, 5, ['a', 'b']]     id(c)= 38605960 id(c[5])= 39219400
# d= [1, 2, 3, 4, 5, ['a', 'b']]     id(d)= 39302472 id(d[5])= 39353672
# **********************************************************************
# a= [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]     id(a)= 38607048 id(a[5])= 39219400
# b= [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]     id(b)= 38607048 id(b[5])= 39219400
# c= [1, 2, 3, 4, 5, ['a', 'b', 'c']]        id(c)= 38605960 id(c[5])= 39219400
# d= [1, 2, 3, 4, 5, ['a', 'b']]             id(d)= 39302472 id(d[5])= 39353672

简单a=b是赋值操作,两个对象完全指向同一个地址,a和b就是同一块地址的两个引用。

c是a进行浅拷贝生成的对象,可以看到a(或b)和c两个对象整体的id是不同的,但是里面的第5个元素-列表的地址却是相同的(指向同一个地址),所以a在浅层次元素层面(不可变)增加一个元素时,c并没跟着增加,但是a的第5个元素-列表在增加一个元素时,c的第5个元素也跟着增加了,这就是因为a和c的第5个元素-列表是指向同一个地址的,这个地址上的值变了,在两个地方会同时改变。

d是a进行深拷贝生成的对象,d的浅层次元素(不可变)和 深层次元素(可变)的地址和a,b,c都不一样,所以,a,b,c无论怎么修改,d都不会跟着改变,这就是深拷贝的结果。

说这么复杂,可以简单理解为:

  • 浅拷贝:原对象的list元素改变的话会改变当前对象,如果当前对象中list元素改变了,也同样会影响原对象。
  • 深拷贝:完全跟以前就没有任何关系了,原来的对象怎么改都不会影响当前对象

那么深拷贝有什么作用呢?

  • 减少内存的使用
  • 以后在做数据的清洗、修改或者入库的时候,对原数据进行复制一份,以防数据修改之后,找不到原数据。

通过案例,你可能就知道深拷贝该怎么使用:Scrapy在爬取数据遇到重复该怎么办?

未经允许不得转载:作者:鳄鱼君Ba, 转载或复制请以 超链接形式 并注明出处 鳄鱼君Ba
原文地址:《Python中你必须要知道的深拷贝和浅拷贝(对象赋值操作)》 发布于2020-03-09

分享到:
赞(2) 赏杯咖啡

评论 抢沙发

4 + 7 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册