在理解这块内容之前需要明白Python中的可变数据类型和不可变数据类型。
参考:https://blog.youkuaiyun.com/PiKeHuPu/article/details/104554268
深浅拷贝
我们通过例子来总结:
from copy import copy,deepcopy
a = 3
c = copy(a)
b = deepcopy(a)
print(id(c))
print(id(b))
结果:
140723133869888
140723133869888
我们可以看到:我们先把copy中的copy和deepcopy导入,然后a=3,之后分别用c和d来接收copy和deepcopy的返回值,打印其地址却发现他们都指向了同一块地址,并且这个地址是和a变量指向的地址是一样的,该地址存放的是3。
好了,这时:我们做出一点点修改:令a = 4
a = 3
c = copy(a)
b = deepcopy(a)
print(id(a))
print(id(c))
print(id(b))
a = 4
print(id(a))
print(id(c))
print(id(b))
我们可以得到如下结果:
140722501906240
140722501906240
140722501906240
140722501906272
140722501906240
140722501906240
观察:我们发现这时只有a变量的结果在修改后发生了改变,那么究竟是为什么?
原因:Python中数据类型有不可变数据类型,整型就属于不可变数据类型,当我们把a赋值为3时,令c和b得到其浅拷贝和深拷贝时,就相当于把c和b都指向了内存中存放3的地址。因为Python自己不需要那么多内存来存放冗余的数据,我拷贝这些文件时,无论是浅拷贝还是深拷贝,无论最终变量标识符有多少,只需要让他们都指向同一个地址就可以。
重点:因为Python在重新给存放不可变数据类型的变量重新赋值时,并不会把其指向地址的内容修改,而是重新“拿”一个新的内存出来存放新的数据。
比较1:
ls = [3, 2, 1]
c = copy(ls)
b = deepcopy(ls)
print(ls,id(ls))
print(c,id(c))
print(b,id(b))
ls[0] += 1
print(ls,id(ls))
print(c,id(c))
print(b,id(b))
结果:
[3, 2, 1] 2167612727816
[3, 2, 1] 2167612727880
[3, 2, 1] 2167633405576
[4, 2, 1] 2167612727816
[3, 2, 1] 2167612727880
[3, 2, 1] 2167633405576
如上述代码和结果:可以看出,ls时一个一维列表,c和b分别是ls的浅拷贝和深拷贝,此时,c和b以及a的地址都是不一样的。
结论1:
-
浅拷贝和深拷贝在拷贝不可变数据类型时,变量都指向同一个地址。
-
浅拷贝和深拷贝在拷贝可变数据类型时,变量都指向不同的地址。
-
在拷贝可变数据类型时,又创建了相同的新数据。
-
因为地址不同,所以修改ls中的数据时,深浅拷贝后得到的数据都不会改变。
比较2:
据说二维的列表就会发生一些变化了。So:
Code First:
ls = [3, 2, [4, 5]]
c = copy(ls)
b = deepcopy(ls)
print(ls,id(ls))
print(c,id(c))
print(b,id(b))
ls[2][0] = 87
print(ls,id(ls))
print(c,id(c))
print(b,id(b))
实验:我们在ls中加了一个列表,并尝试两次输出,之间尝试修改ls二位列表中的数据。这里对ls[2][0]的数据进行了修改。
结果:
[3, 2, [4, 5]] 2654706295368
[3, 2, [4, 5]] 2654727038984
[3, 2, [4, 5]] 2654707561160
[3, 2, [87, 5]] 2654706295368
[3, 2, [87, 5]] 2654727038984
[3, 2, [4, 5]] 2654707561160
现象:我们可以看到,修改ls[2][0]的值以后,深拷贝中的内容并没有发生改变,而浅拷贝中的内容发生了变化。可我们观察他们的地址并不一样,为什么呢?
解释:浅拷贝在完成操作后,只对第一层进行拷贝(我们这里把大于第一层的称为深层),换句话说,浅拷贝完整的复制了ls[i](这里表示第一层)即第一层的数据。这里c得到的是第一层,第二层被第一层所指向。所以当我们修改深层数据时,浅拷贝的内容也会跟着发生变化。
深拷贝就u不一样了,深拷贝会把所有可变数据类型都赋值一遍。(这里好好理解什么是可变数据类型)