复制的"玄学" - 交互式学Python | 莫烦Python

复制的"玄学"

作者: 莫烦 编辑: 莫烦 2021-06-05

为什么说复制是玄学呢?其实如果你是编程小白,在学习 Python 或者任何语言的时候, 都会遇到这个问题,我既然是复制了一个复制品,为什么我改动这个复制品,原物也会发生改变呢? 如果我没有对内存机制的一个理解,这件事情对于我就是一门玄学

好在我今天就帮对程序中的复制还不太清楚的同学们,解释一下你在复制时,究竟复制的是什么?

cp

注:不同的语言中,对复制有着不同的定义,但是都离不开复制地址和复制值这两种说法。我们下面就来具体说明吧。

我的确复制了呀

先看看下面这种复制,为了验证我的确是复制了,我们使用列表的复制功能, 先复制一份列表 l,存储在 _l 中。然后修改复制后的数值,看看源列表有没有同样被修改?

从结果看出,我们的确复制了列表里所有的值,对复制后的列表的修改,没有影响到源列表。但其他时候也一样么?

其实你就搞了个隐分身

下面我们在用列表把列表里再放一个列表,copy() 源列表 l_l。这次对 _l 里边的小列表修改,看看源列表是什么变化。

当你运行后,你会发现,源列表居然变了!不明真相的我认为这是玄学! 明明都复制了,为什么还会关联到源列表?难不成我用的是量子计算机,有量子纠缠??

我们再来看看另外一种情况,我把类别的实例存放到 l 列表中,然后 copy 再修改,看看什么情况?

明明源列表是 mp3 的,怎么被复制后的列表改变成了 mp4 了,自动升了各级?查阅 Python 的说明书,你就会发现, 原来在 Python 中复制东西,有两种方式,一种是深拷贝,一种是浅拷贝。

深拷贝与浅拷贝

说英文可能会更加好理解一点,深拷贝是 Deep Copy,浅拷贝是 Shallow Copy。 Deep copy 就是我们通常意义上的复制,把东西全部再造了一遍,彻底成为了两个独立的个体。 而 Shallow Copy, 其实也有一点影子拷贝的意思,我复制出来的是你的一个影子,一个投影成像。 所以真实的实体是没有被复制的,我只复制了这个实体的一个投影而已。

那么在上面的案例中,比如列表中的列表,列表中的 Class 实例,其实都是复制了他们的投影,没有动到真身。 想要让投影改变,那就必须动到真身。所以在修改 _l 中的拷贝时,它就回去找真身了,那么真身就会被改变了。

但为什么复制数值的时候,源列表中的数值没有改变呢?难道数值没有真身? 这可能就有点玄学了,哈哈。Python 他在创造之初,就有这么个约定,列表中直接存放的数值,字符,和存 class 实例,列表,字典不同。 对数值字符的复制,直接是复制的值,而不是一个投影。

那么问题来了,如果我想做对存放实例的列表做 Deep Copy 深拷贝的时候咋办?

Python 自带了一个 copy 的库,里面就有一个 deepcopy,用这个你就能实现完全的深拷贝。上面尝试了深拷贝列表当中的列表。 你也可以尝试将我上面那个 class 复制的代码贴上,用 deepcopy 来试试,看看会怎样?

总结

这就是 Python 比较玄学的地方。之后我们学习到 Python 科学计算库 Numpy 的时候,这种类似的玄学又会从天而降。如果你没弄懂这些, 有时候出错了都不知道是哪错了,其实很有可能就是你浅复制后,改变了不该被改变的值。

而且我们我们也会讲,浅复制的优势就是。复制是需要内存和时间的,因为浅复制没有真正复制,所以并不需要耗多少内存和时间, 所以浅复制也是有优势的,一个字


降低知识传递的门槛

莫烦很常从互联网上学习知识,开源分享的人是我学习的榜样。 他们的行为也改变了我对教育的态度: 降低知识传递的门槛免费 奉献我的所学正是受这种态度的影响。 通过 【赞助莫烦】 能让我感到认同,我也更有理由坚持下去。