深浅拷贝
在说深浅拷贝之前,先说一下is 与 == 两个比较:
is:判断两个引用是否指向同一个对象。
==:判断两个引用指向的对象值是否相等。
我们打开IDLE:

可以看到,a is b 同一个对象,即a和b指向同一个对象。c is d 不是同一个对象,即不c 和 d不是指向同一个对象。
我们查看a,b,c,d的id:

可以看到,a和b的地址一样,即指向同一个对象。c和d的地址不一样,即不是指向同一个对象,a和b指向的对象值即使相同,但占据着不同的内存地址,是两个不同的对象。
注:id()用于查看对象地址。a和b是同一个对象,c和d不是同一个对象,这个和python中的小整数池有关,是python提高性能的一种方式。

从上图可以看到, == 只是比较两个对象的值。
深浅拷贝:
浅拷贝: 拷贝的是对象的引用,如果原对象改变,相应的拷贝对象也会发生改变
深拷贝: 拷贝对象中的每个元素,拷贝对象和原有对象不在有关系,两个是独立的对象
a,浅拷贝:
a = [1, 2, 3] b = list(a) c = a.copy() print(id(a)) print(id(b)) print(id(c)) print(a) print(b) print(c) a.append(4) print(a) print(b) print(c)
执行效果:
1993698794944 1993697870272 1993698868096 [1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3, 4] [1, 2, 3] [1, 2, 3]
可以看到,list()和copy()只是对值进行了拷贝,会重新开辟一个内存空间存放拷贝后的值。
那如果被拷贝的对象中,有可变对象怎么办,如列表。我们来看下面的例子:
a = [1, 2, 3, [11, 22]] b = list(a) c = a.copy() a[-1].append(33) print(a) print(b) print(c)
a.append(4) print(a) print(b) print(c)
执行结果:
[1, 2, 3, [11, 22, 33]] [1, 2, 3, [11, 22, 33]] [1, 2, 3, [11, 22, 33]] [1, 2, 3, [11, 22, 33], 4] [1, 2, 3, [11, 22, 33]] [1, 2, 3, [11, 22, 33]]
可以看到,当a执行append(4)时,确实对b和c没有影响,因为a,b,c都是不同对象。
但是当a对其中的[11, 22]进行append(33)时,b和c都被影响了。
原因:因为对a进行list()或copy()拷贝时,[11, 22]的拷贝只是拷贝了其对象,即b,c中的[11, 22]和a中的[11, 22]是相同对象。
再看下面的代码:
a = [1, 2, 3, (11, 22)] b = list(a) c = a.copy() a[-1] += (33,) print(a) print(b) print(c)
执行效果:
[1, 2, 3, (11, 22, 33)] [1, 2, 3, (11, 22)] [1, 2, 3, (11, 22)]
可以看到,a中的(11, 22)改变后,b和c中并未收到影响。
原因:(11, 22)是元组,是不可变变量,(11,22)+ (33,)时,其实时新创建了一个对象。
我们验证一下:
a = [1, 2, 3, (11, 22)] b = list(a) c = a.copy() a[-1] += (33,) print(id(a[-1])) print(id(b[-1])) print(id(c[-1]))
执行效果:
[1, 2, 3, (11, 22, 33)] [1, 2, 3, (11, 22)] [1, 2, 3, (11, 22)] 2634394742592 2634393769728 2634393769728
可以看到,b和c的(11, 22)是同一个对象,但是a的(11, 22)经过 + 操作后,已经是另外一个对象了。
b,深拷贝
如果我们要避免浅拷贝带来的困扰,我们可以使用深拷贝。深拷贝只会拷贝值后重新创建一个对象(开辟新的地址)。
使用深拷贝,需要导入深拷贝方法:
from copy import deepcopy
from copy import deepcopy a = [1, 2, 3, [11, 22]] b = deepcopy(a) print(id(a[-1])) print(id(b[-1])) a[-1].append(33) a.append(4) print(a) print(b)
执行效果:
2085416820032 2085416892544 [1, 2, 3, [11, 22, 33], 4] [1, 2, 3, [11, 22]]
可以看到,当对a进行深拷贝得到b时,二者的[11, 22]的内存地址不一样,说明不是同一个对象,只是拷贝了值而已。
对a进行元素操作,内部列表进行操作,都不会影响b。
浙公网安备 33010602011771号