前言

“为什么要学习深浅拷贝,它有什么应用场景呢?”

“理解深浅拷贝能让我们避开哪些坑呢?”

在文章开始之前,不妨思考一下上面的问题,学习任何一门语言,基础都很重要,“基础不牢,地动山摇”;你现在觉得无所谓,那是你还没有掉进坑里。话不多说,直接进入今天的正文。

正文

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(对象):

完全拷贝,不论外层内层地址都改变(完全独立,互不影响)。深拷贝产生的副本可以随意修改,而不用担心会影响原始值。