Python深拷贝与浅拷贝说明与举例
Posted 詩和遠方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python深拷贝与浅拷贝说明与举例相关的知识,希望对你有一定的参考价值。
知识准备
- 可变类型(mutable):list、set、dict可变类型,支持原地址直接改变元素(item)的值
- 不可变类型(immutable):int、float、str、tuple等均为不可变类型,不支持原地址改变元素的值
相关例子见另一篇博文深刻理解python变量
浅拷贝说明与举例
无拷贝
a = [1,2,(3,4)]
b = a
b[0] = 4
print('id(a) =',id(a))
print('id(b) =',id(b))
print('a =',a)
print('b =',b)
结果:
id(a) = 2848475391240
id(b) = 2848475391240
a = [4, 2, (3, 4)]
b = [4, 2, (3, 4)]
直接赋值,相当于取了别名,其地址是一样的,所以对b元素的修改,也影响了a。
浅拷贝(Shallow Copy)
使用构造函数list
,切片或copy.copy()函数可浅拷贝列表
a = [1,2,[3,4]]
b = list(a) # 拷贝列表a值,而不是引用
b[0] = 4
print('id(a) =',id(a))
print('id(b) =',id(b))
print('a =',a)
print('b =',b)
结果:
id(a) = 2848460025992
id(b) = 2848475458632
a = [1, 2, [3, 4]]
b = [4, 2, [3, 4]]
发现a和b的地址不同,对b的改变不会影响a,但这仅对不可变元素成立,因为对不可变元素的修改,会生成新的对象,从而指向新的地址,而原来a列表中的元素还是指向老地址。
由于b[2]是一个List,为可变类型,若对b[2]元素的进行修改,a也会一起变:
b[2][0] = 100
print('id(a) =',id(a))
print('id(b) =',id(b))
print('a =',a)
print('b =',b)
结果:
id(a) = 2848481489096
id(b) = 2848477955016
a = [1, 2, [100, 4]]
b = [4, 2, [100, 4]]
a[2][0]和b[2][0]的值都变为100。
所以浅拷贝只是拷贝了第一层地址,如果列表中含可变类型元素,则对副本的修改也可能会影响原来的值。
深拷贝(Deep Copy)
为了解决以上问题,python有一个copy模块可以实现深拷贝,deepcopy为深拷贝,copy为浅拷贝。
import copy
a = [1,2,[3,4]]
b = copy.deepcopy(a)
b[2][0] = 100
print('id(a) =',id(a))
print('id(b) =',id(b))
print('a =',a)
print('b =',b)
结果:
id(a) = 2848487131400
id(b) = 2848487129480
a = [1, 2, [3, 4]]
b = [1, 2, [100, 4]]
b[2][0]的值不再影响a[2][0]。
深拷贝不仅复制列表第一层的地址,若列表中含有可变类型元素,则其对应元素也一起复制,依此类推,有多少层可变类型引用,就复制多少层。
可变与不可变元素深拷贝的区别
同样是深拷贝,当所拷贝对象可变或不可变属性不一样时,情况是不一样的:
import copy
a = [1,(2,3),[4,5]]
b = copy.deepcopy(a)
print('a = ',id(a))
for x in a: print(' ',id(x))
print('b = ',id(b))
for x in b: print(' ',id(x))
结果:
a = 2848483339784
140711207018896
2848488706632
2848487130696
b = 2848487129608
140711207018896
2848488706632
2848482189128 (地址不同)
以上1和(2,3)均为不可变类型,所以即便是深拷贝,在拷贝后的列表b中,其地址还是一致的,但[4,5]是可变类型,拷贝后地址也变了。
画图助理解
最后画一张简单的图帮助理解(add为address缩写):
以上是关于Python深拷贝与浅拷贝说明与举例的主要内容,如果未能解决你的问题,请参考以下文章