浅拷贝和深拷贝函数是专门用于可变数据类型list、set、dict的函数。效果是当一个值指向另一个值时,不会影响指向的值。如果指向的数据是可变数据,一旦修改,指向的数据也会随之改变。什么是可变数据和不可变数据?让我们举个例子。整数是不可变数据,那为什么是不可变数据呢?一条数据是否可变与python的缓存机制有关。当一个数据发生变化时,如果它的内存地址没有变化,就说明它是一个可变数据。比如我们现在创建一个变量,它的值为a,它的值为100,然后让这个值发生变化,观察变量的内存地址有没有变化。a=100print(a,id(a))#1001610845392a+=100print(a,id(a))#2001610848592我们发现值变了,变量的内存也变了,所以我们再创建一个变量b,值也是整数100b=100print(b,id(b))#1001610845392发现b的内存地址和a的内存地址是一样的,也就是说对于a数据类型如整型,一个数占用一个内存地址,当指向这个值的变量发生变化时,需要改变的不是变量的值,而是变量需要找到变化值的内存地址,以及然后再次指向它。只要你的硬件不重启,那么这个内存地址就永远不会改变,这样的数据就是不可变数据。那么反之就是可变数据,也就是说当变量指向的值发生变化时,实际上这个内存地址处的值也发生了变化,这就是可变数据类型。比如列表,列表改变后,在原来的基础上改变,所以内存地址不会改变,这就是可变数据类型,可变数据类型没有内存缓存机制,不能节省内存,所以它完全相同的数据,它们的内存地址可能不同。a=[1,2]print(a,id(a))#[1,2]1528536069896a.append(3)print(a,id(a))#[1,2,3]1528569896#b和a的值相同,但内存地址不同b=[1,2,3]print(b,id(b))#[1,2,3]1528536069832那么copy的功能是什么?在我们实际工作中,经常用到的一个操作就是定义一个变量,它的值直接赋值给一个原变量。但是,定义了变量之后,我们肯定不是拿它来装饰,而是用来做计算或者临时存储的。那么原变量的值就会改变,问题就来了。如果是一个不可变的数据就可以了。如果是可变数据,直接赋值的内存地址是一样的。如果变量的值发生变化,则同一内存地址的值也会发生变化。我们要暂时存储的值已经不是我们想要的值了,这在很多时候是我们不想看到的结果。我们以一个整数为例。变量a直接赋值给变量b。此时变量a和b的值是一样的,但是如果变量a的值发生变化,根本不会影响变量b的值。a=100print(a,id(a))#1001610845392b=aprint(b,id(b))#1001610845392a+=100print(a,id(a))#2001610848592print(b,id(b))#1001610845392但是如果是可变数据就不是这样a=[1,2]print(a,id(a))#[1,2]2077688035080b=aprint(b,id(b))#[1,2]2077688035080a.append(3)print(a,id(a))#[1,2,3]2077688035080print(b,id(b))#[1,2,3]2077688035080不可变数据的这个特性是既是优势也是劣势。缺点是如果我们想保存变量a变化前的状态,是无法保存的。这时候就出现了一个copy函数,可以把可变数据变成不可变数据的效果。浅拷贝使用copy函数,将变量a作为参数放入函数中,使用变量b接收函数的返回值,成功复制变量a。变量b和变量a的内存地址不同,所以当他们一方改变后,另一方的数据不会受到影响。#copy函数不能直接使用,需要使用import导入copy模块,copy模块的copy函数是浅拷贝importcopya=[1,2,3]#变量b不再直接赋值给变量a,但是通过copy函数b的返回值=copy.copy(a)#它们的值是一样的,只是内存地址不同,所以它们之间的任何变化都不会影响到第二方.print(a,id(a))#[1,2,3]2343743813320print(b,id(b))#[1,2,3]2343743813192a.append(4)print(a,id(a))#[1,2,3,4]2343743813320print(b,id(b))#[1,2,3]2343743813192但是如果变量a是二级容器或者更高一级的容器,浅拷贝就无法复制二级容器或多级容器,所以当二级容器或多级容器发生变化时,它仍然会发生变化,因为浅拷贝只能复制一级容器,所以多级容器的内存地址仍然相同。importcopya=[[66,88],2,3]b=copy.copy(a)print(a,id(a))#[[66,88],2,3]2431683163720print(b,id(b))#[[66,88],2,3]2431683162184#改变二级容器a[0].append(100)print(a,id(a))#[[66,88,100],2,3]2431683163720print(b,id(b))#[[66,88,100],2,3]2431683162184#浅拷贝不能复制二级及以上容器print(id(a[0]))#1582481372872print(id(b[0]))#1582481372872深拷贝和浅拷贝只能拷贝一级容器,于是深拷贝诞生了,可以拷贝各级容器。importcopya=[[66,88],2,3]#深拷贝使用deepcopy函数b=copy.deepcopy(a)print(a,id(a))#[[66,88],2,3]2168411158088print(b,id(b))#[[66,88],2,3]2168411156552a[0]。append(100)print(a,id(a))#[[66,88,100],2,3]2168411158088print(b,id(b))#[[66,88],2,3]2168411156552#深拷贝各级容器print(id(a[0]))#2168411158216print(id(b[0]))#2168411122760总结要使用深浅拷贝,需要导入copy模块;浅拷贝使用copy函数,只能拷贝一级容器的所有元素;深拷贝使用deepcopy功能,可以拷贝各级容器的所有元素;标准库中只对copydeepcopy和deepcopy两个函数对外开放;因为深拷贝要拷贝的元素比较多,所以速度会远不如浅拷贝。在编程过程中,应注意避免不必要的系统负担;python中不可变数据有Number、string、tuple,可变数据有list、set、dict;而复制是专门为可变数据提供的,所以深浅复制只适用于list、set、dict。但这没有意义。
