浅拷贝与深拷贝是一个常问的问题,仔细看一看基本就会了。
讲深浅拷贝之前先引入可变变量与不可变变量这两个概念。
1、可变变量,值可以改变:
list列表,dict字典
可变类型,添加或者修改数据时,变量对应的内存地址不会改变。也就是可变类型,一直在引用原来的内存地址。
注意,如果是重新赋值,内存地址就会发生改变。
而del 变量名 则只是删除一个指针,不删除变量。
2、不可变变量,值不可以改变:
数值类型int、long、bool、float
字符串str
元组tuple
不可变类型,一旦被重新赋值,变量对应的内存地址就会发生改变。
然后深浅拷贝就是关于可变变量与不可变变量引出的问题,请看第一个例子
a=1
b=[1]
print(id(a),id(b),id(b[0]))
out:
4308636736 140248010514248 4308636736
·
不难看出 a与b[0]的地址是一样的,a与b的地址不同,但是a与b[0]指向的是同一块地址,那么我们可以的出这么个结论,a作为一个不可变变量,指向1的地址,b为可变变量,但是b中的元素b[0]依旧指向1的地址。这体现了列表的性质,列表本质上是一个数组,但我们知道,数组是定长的,但是python里面的列表可以放各种类型的数据,原因在于这个列表里面存放的是引用,这个引用最终指向了存储的数据,好了我们知道这条性质,来看下个例子。
a=1
b=[1]
c=a
a=2
d=b
b.append(2)
print(a,c)
print(b,d)
print(id(a),id(c))
print(id(b),id(d))
out:
2 1
[1, 2] [1, 2]
4494939232 4494939200
140421169209160 140421169209160
·
可以发现,等号对于不可变变量是值传递,归根结底是a传了个引用过去,使得c指向了1的地址,但是作为可变变量,当a=2时候,a指向2的地址,而c的地址还停留在a之前传给他1的地址上,最终a=2,b=1且地址不同。
对d=b这个式子来说,也是b传了个引用过去给d,但是b作为可变变量,即使增加了个数据,地址仍然不变,因此最终导致b,d地址一致。
这个例子看明白的应该是理解可变变量与不可变变量,在碰到等号情况下,两者的区别,下个面讲深浅拷贝。
·
首先深浅拷贝都对于可变变量而言的,不可变变量无论深浅拷贝,地址都不变,如下所示。
import copy
a=1#不可变变量
b=copy.copy(a)
c=copy.deepcopy(a)
print(id(a),id(b),id(c))
out:
4378739776 4378739776 4378739776
import copy
a=[1]#可变变量
b=copy.copy(a)
c=copy.deepcopy(a)
print(id(a),id(b),id(c))
140539880176840 140539880176456 140539880441544
那么下面讨论可变变量深浅拷贝情况
import copy
a=[1,[1],2,[2]]
b=copy.copy(a)
c=copy.deepcopy(a)
print("a,b,c地址:",id(a),id(b),id(c))
for i in range(len(a)):
print("第{}项地址".format(i),id(a[i]),id(b[i]),id(c[i]))
out:
a,b,c地址: 140565138540360 140565138540424 140565138541384
第0项地址 4490380352 4490380352 4490380352
第1项地址 140565138238856 140565138238856 140565138540296
第2项地址 4490380384 4490380384 4490380384
第3项地址 140565138238472 140565138238472 140565138587592
·
可以看出,深浅拷贝a,b,c地址都不同,但是里面的第*项的地址,按照可变变量与不可变变分类,可变变量地址一律相同,不可变变量浅拷贝地址和原地址相同,深拷贝地址是和原地址不同。