前言
“为什么要学习深浅拷贝,它有什么应用场景呢?”
“理解深浅拷贝能让我们避开哪些坑呢?”
在文章开始之前,不妨思考一下上面的问题,学习任何一门语言,基础都很重要,“基础不牢,地动山摇”;你现在觉得无所谓,那是你还没有掉进坑里。话不多说,直接进入今天的正文。
正文
1、传递引用与拷贝
在正式学习深浅拷贝之前,我们先要弄清什么是传递引用
#定义一个列表
a=[1,2,3,4]
#把a的值传递给b(把a的值赋给b)
b=a
#来看看b的值
b
>>>1,2,3,4
'''那么问题来了,b的值与a的值一样,是不是说明a的值被拷贝了然后传给b呢?
我们继续往下看:
想要回答这个问题,我们需要知道,
所谓拷贝就是把a的数值复制后在内存中另开辟一个空间进行存储;
那么如果b=a是拷贝a的值的话,那么他们的内存地址应该是不同的,来验证一下:
'''
id(a)
>>>2156804875464
id(b)
>>>2156804875464
'''
验证的结果表面,b的值并不是a的拷贝,而是a的内存地址引用。
这里有点绕,简单点说:
a的值存储在内存中占一定的内存空间;
而b的值并不是再开辟一个空间进行存储,只是引用了a的内存地址,所以值与a的值一样;
既然b是a地址引用,那么如果改变a的值,按理说b的值也会相应更改,验证一下:
'''
#把列表a的一个元素改为5
a[0]=5
a
>>>[5,2,3,4]
b
>>>[5,2,3,4]
通过上面的解释,大家应该对传递引用与拷贝有了一定的认识,简单来说:传递引用只是引用了内存地址,并不会开辟空间进行存储。因为a和b是一个内存地址,改变a的值,相应的b就会随之更改。
明白了传递引用,我们再来看拷贝:
#拷贝a
import copy
a=[1,2,3,4,5]
a_copy=copy.copy(a)
a_copy
>>>
Out[1]:
[1, 2, 3, 4, 5]
#可以看到a_copy的值与a的值一样,那么内存地址呢?
id(a)
>>>
Out[2]:
2156804090696
id(a_copy)
>>>
Out[3]:
2156803993544
'''
可以看到,值一样,地址不一样;说明a,b两个变量开辟了两个独立的内存空间存储,
所以用copy()方法,是拷贝。
'''
2、浅拷贝与深拷贝
简单的说,所谓的拷贝,就是在内存中开辟一个空间存储相同的值,其特点是值相同,地址不同,也就是两个值都占用内存空间进行独立存储。拷贝为什么又分为浅拷贝和深拷贝,它们有什么区别呢?其实把拷贝分为浅拷贝与深拷贝主要的原因是元素的多层嵌套问题,直接上例子:浅拷贝
#定义一个由两层列表组成的值a
a=[1,2,3,[4,5,6]]
#浅拷贝a的值,看看效果
a_copy=copy.copy(a)
#输出浅拷贝的值a_copy
a_copy
Out[4]:
[1, 2, 3, [4, 5, 6]]
#改下a的第一层元素的值,看看浅拷贝的a_copy有没有变化
a[0]=5
#输出更改后a的值
a
Out[5]:
[5, 2, 3, [4, 5, 6]]
#再看下a_copy的值
Out[6]:
[1, 2, 3, [4, 5, 6]]
#*从结果上看,改变a第一层元素的值,其浅拷贝a_copy的值不变
-------------------------------------------------------
#改下a的第二层元素的值,看看浅拷贝的a_copy有没有变化
a[3][1]=9
#输出更改后a的值
a
Out[6]:
[1, 2, 3, [4, 9, 6]]
#再看下a_copy的值
Out[7]:
[1, 2, 3, [4, 9, 6]]
#*从结果上看,改变a第二层元素的值,其浅拷贝a_copy的值改变
2、深拷贝
#定义一个由两层列表组成的值a
a=[1,2,3,[4,5,6]]
#深拷贝a的值,看看效果
a_deepcopy=copy.deepcopy(a)
#输出深拷贝a_deepcopy的值
Out[1]:
[1, 2, 3, [4, 5, 6]]
#改下a的第一层元素的值,看看深拷贝的a_deepcopy有没有变化
a[0]=5
#输出更改后a的值
a
Out[2]:
[5, 2, 3, [4, 5, 6]]
#再看下a_deepcopy的值
Out[3]:
[1, 2, 3, [4, 5, 6]]
#改下a的第一层元素的值,其深拷贝a_deepcopy的值不变
-------------------------------------------------------
#改下a的第二层元素的值,看看拷贝的a_deepcopy有没有变化
a[3][1]=9
#输出更改后a的值
a
Out[4]:
[1, 2, 3, [4, 9, 6]]
#再看下a_deepcopy的值
Out[5]:
[1, 2, 3, [4, 5, 6]]
#*从结果上看,改变a第二层元素的值,其深拷贝a_deepcopy的值依然不变
3、总结浅拷贝:copy.copy(对象):
只拷贝对象外层(第一层)元素,而对内部元素进行引用;即外层地址改变(独立存储、互不干涉),内层地址不变(地址共享,相互影响)。整体地址改变。简单的说:就是在使用浅拷贝时,改变原值外层元素时,浅拷贝的值不受影响,但是如果是内层元素,浅拷贝的值会相应更改。原因是,浅拷贝只是拷贝了外层的元素,而内层的元素是地址的引用,所以,在浅拷贝的情况下更改内层元素,浅拷贝的值会改变。深拷贝:deepcopy(对象):
完全拷贝,不论外层内层地址都改变(完全独立,互不影响)。深拷贝产生的副本可以随意修改,而不用担心会影响原始值。