深浅拷贝

在说深浅拷贝之前,先说一下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。

posted @ 2022-04-02 11:10  Target_L  阅读(47)  评论(0)    收藏  举报