Python中对象的引用与复制
在python进行像b = a这样的赋值时,只会创建一个对a的新引用,使a的引用计数加1,而不会创建新的对象:
1 2 3 4 5 6 7 8 9 10 11 | >>> a = 'xyz' >>> import sys >>> sys.getrefcount(a) 3 >>> b = a >>> sys.getrefcount(b) 4 >>> id (a) 88292288L >>> id (b) 88292288L |
这样,当引用的对象是可变对象的时候(列表,字典,可变集合等),会产生意料之外的行为:
1 2 3 4 5 | >>> a = [ 1 , 2 , 3 , 4 ] >>> b = a >>> b.append( 5 ) >>> a [ 1 , 2 , 3 , 4 , 5 ] |
因为a和b引用的是同一对象,改变其中一个,另外一个也会随之改变。当我们想建立一个副本而不是引用时,可以复制对象。
复制对象一般使用copy模块:
1 2 3 4 5 6 7 8 | >>> a = [ 1 , 2 , 3 , 4 ] >>> import copy >>> b = copy.copy(a) >>> b.append( 5 ) >>> b [ 1 , 2 , 3 , 4 , 5 ] >>> a [ 1 , 2 , 3 , 4 ] |
这样就可以了,但这种复制是一种浅复制,复制的新对象中包含的是对原始对象中的项的引用,如果对象的项为可变对象,也会产生不可控行为:
1 2 3 4 5 6 7 | >>> a = [ 1 , [ 1 , 2 ]] >>> b = copy.copy(a) >>> b[ 1 ].append( 3 ) >>> b [ 1 , [ 1 , 2 , 3 ]] >>> a [ 1 , [ 1 , 2 , 3 ]] |
这时候就要使用深复制了。深复制将创建一个新对象,并递归地复制它所包含的所有对象:
1 2 3 4 5 6 7 | >>> a = [ 1 , [ 1 , 2 ]] >>> b = copy.deepcopy(a) >>> b[ 1 ].append( 3 ) >>> b [ 1 , [ 1 , 2 , 3 ]] >>> a [ 1 , [ 1 , 2 ]] |
对于不可改变的对象而言(字符串,数字,元组)等,没有必要拷贝,因为它们是不可改变的,不用担心会不经意间改动了它们。拷贝操作也只会得到原对象:
1 2 3 4 | >>> a = ( 1 , 2 , 3 ) >>> b = copy.copy(a) >>> a is b True |
对于可变对象来(列表,字典,可变集合)来说,可以分别使用内置函数list(),dict(),set()来进行浅复制,速度是比使用copy模块快的。
列表也可以使用切片进行浅复制:
1 2 3 4 5 6 | >>> a = [ 1 , 2 , 3 , 4 ] >>> b = a[:] >>> a is b False >>> b [ 1 , 2 , 3 , 4 ] |
对序列数据类型(字符串,列表,元组)进行*操作时,也仅仅是复制了对象中项的引用,如果使用*创建一个多维列表:
1 2 3 4 5 6 | >>> a = [ 1 , 2 , 3 ] >>> b = [a] >>> c = b * 3 >>> a.append( 4 ) >>> c [[ 1 , 2 , 3 , 4 ], [ 1 , 2 , 3 , 4 ], [ 1 , 2 , 3 , 4 ]] |
最好是在列表推导中使用浅复制来创建多维列表,可以避免隐式的引用共享:
1 2 3 4 5 | >>> a = [ 1 , 2 , 3 ] >>> c = [ list (a) for i in range ( 3 )] >>> a.append( 4 ) >>> c [[ 1 , 2 , 3 ], [ 1 , 2 , 3 ], [ 1 , 2 , 3 ]] |
分类:
Python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)