1、数据在内存中的存储(一级指针)
指针 是C++中的概念,为了方便讲清楚深浅拷贝,暂借C++中的术语。
a=1
b=a
变量a和变量b在内存中的存储如下图:
此时若要修改变量a或变量b的值,假设修改a的值
a=2
编译器在栈中分配一块内存,存储2,假设地址为0002,如下图:
如果没有变量指向地址:0001,编译器会自动释放掉地址0001占用的内存,这里变量b还在指向地址0001,故没有被释放。
我们用一段程序来验证上面的解释:
a=1
b=a
print("a的内存地址:%s" %id(a)) #打印a的内存地址
print("b的内存地址:%s" %id(b)) #打印b的内存地址
a=2
print("a的内存地址:%s" %id(a)) #打印a的内存地址
print("b的内存地址:%s" %id(b)) #打印b的内存地址
输出:
a的内存地址:1747676640
b的内存地址:1747676640
a的内存地址:1747676672
b的内存地址:1747676640
2、数据在内存中的存储(多级指针)
a=[[1,2],3,4]
b=a
变量a和变量b在内存中的存储大致如下图:
此时,如果修改a中的元素或者b中的元素都会同时引起a、b变化,这就是下文中所要提到的浅拷贝。
下面用代码验证上面的解释:
a=[[1,2],3,4]
b=a
b[1]=33 #a[1]和b[1]会同时被修改成33
print(a)
print(b)
输出:
[[1, 2], 33, 4]
[[1, 2], 33, 4]
3、赋值拷贝
修改变量a的任一元素或修改变量b的任一元素,a和b的值均会一起变
a=[[1,2],3,4]
b=a
print("修改元素前a= %s" %a)
print("修改元素前b= %s" %b)
b[1]=33 #修改二级指针对应的元素,a和b的值均会变化
print("修改元素后a= %s" %a)
print("修改元素后b= %s" %b)
输出:
修改元素前a= [[1, 2], 3, 4]
修改元素前b= [[1, 2], 3, 4]
修改元素后a= [[1, 2], 33, 4]
修改元素后b= [[1, 2], 33, 4]
4、浅拷贝
浅拷贝使用copy
4.1、浅拷贝二级指针元素的影响
修改变量a的二级指针所指的元素,只有a值会变,b值不会被改变
a=[[1,2],3,4]
b=a.copy()
print("修改元素前a= %s" %a)
print("修改元素前b= %s" %b)
b[1]=33 #修改二级指针对应的元素,只有b的值会变化
print("修改元素后a= %s" %a)
print("修改元素后b= %s" %b)
输出:
修改元素前a= [[1, 2], 3, 4]
修改元素前b= [[1, 2], 3, 4]
修改元素后a= [[1, 2], 3, 4]
修改元素后b= [[1, 2], 33, 4]
4.2、浅拷贝三级指针元素的影响
修改变量a或变量b的三级指针所指的元素,a和b的值均会一起变
a=[[1,2],3,4]
b=a.copy()
print("修改元素前a= %s" %a)
print("修改元素前b= %s" %b)
b[0][0]=11 #修改三级指针对应的元素,a和b的值均会变化
print("修改元素后a= %s" %a)
print("修改元素后b= %s" %b)
输出:
修改元素前a= [[1, 2], 3, 4]
修改元素前b= [[1, 2], 3, 4]
修改元素后a= [[11, 2], 3, 4]
修改元素后b= [[11, 2], 3, 4]
5、深拷贝
深拷贝需导入import copy
深拷贝,各元素之间互不影响
copy.copy()函数是浅拷贝,与copy函数功能一致。
copy.deepcopy()函数是深拷贝
import copy
a=[[1,2],3,4]
b=copy.deepcopy(a) #深拷贝
print("修改元素前a= %s" %a)
print("修改元素前b= %s" %b)
b[0][0]=11 #深拷贝,各变量互不影响
print("修改元素后a= %s" %a)
print("修改元素后b= %s" %b)
输出:
修改元素前a= [[1, 2], 3, 4]
修改元素前b= [[1, 2], 3, 4]
修改元素后a= [[1, 2], 3, 4]
修改元素后b= [[11, 2], 3, 4]