人海茫茫
相识真好

决战Python之巅(六)---补充篇

前言

本来是想在上一篇最后直接加的,但是觉得接着写篇幅可能会比较长,可能你们就翻不到那边,所以决定重开一篇,来好好写写list的深浅Copy。(我也是刚看完视频,趁热打铁来复盘一下)。
敲黑板!!!好好看!!有点绕,但是看懂了就懂了,不懂的可以评论提问。

知识回顾

首先,先看一段代码:

a = 1
b = a

问题1:b = ? 很简单,答案是1。
那么,这样呢?

a = 1
b = a
a = 2

问题2:请问现在b = ? 也很简单,b还是等于1。为什么呢?不是说b = a了嘛?既然a改了b为什么没改呢?
请看下面:
决战Python之巅(六)---补充篇
当运行完 b = a后,大家可以发现,a 和 b的内存地址是一样,也就是说a和b都指向了140716819469344这个内存地址。那么当我对a重新赋值时,大家可以看到:
决战Python之巅(六)---补充篇
a指向的内存地址改变了,而b还是指向原来的内存地址。也就是说,除非你重新给b赋值或者再运行一次 b = a ,否则b指向的内存地址就会一直是原来的,无论a变成什么,都不会影响到b。这么说可能有点干…画个图就知道了。
一开始变量a指向的是1的内存地址,
决战Python之巅(六)---补充篇
执行完b = a 后,a和b都指向了这个内存地址:
决战Python之巅(六)---补充篇
接下来 a = 2:
决战Python之巅(六)---补充篇
a就指向了另一个内存地址,而b不变。
这是前提。
接下来讲list,首先还是一样,初始化两个变量:
决战Python之巅(六)---补充篇
毋庸置疑,L2 肯定是 [1,2,3,4,5,6],对吧。好,那接下来,我要将L1的第一个元素换成0:
决战Python之巅(六)---补充篇
那么,请问,现在L2是多少呢?根据我上面讲的,照道理应该还是[1,2,3,4,5,6],那真的是这样的吗?我们试验一下:
决战Python之巅(六)---补充篇
What???为什么L2也改变了?Why??
回答这个问题之前,照例我们看一下两个list的内存地址:
决战Python之巅(六)---补充篇
list的内存地址还是一样,没什么问题,那么,改了L1之后的内存地址呢?
决战Python之巅(六)---补充篇
????为什么我改了之后L1的内存地址没有变呢?
首先大家要知道的是,列表里每一个元素都是一个独立的个体,它们都有自己的内存地址:
决战Python之巅(六)---补充篇
这就相当于,唔…我用Alex的例子来解释:list就相当于一个容器,假设就是杯子吧,元素是独立的个体,就把它们当做是枣子吧,虽然把枣子放进了杯子,但他们还是独立存在的,也就是说每一个枣子,啊呸,每一个元素都有独立的内存地址(从上图我们也可以看得出来),其次杯子本身也是有内存地址。现在我们初始化了一个list为L1,它有一个内存地址为ID1,然后又重新初始化了一个list为L2,执行L2 = L1,那么可以知道L2指向的是L1实际的内存地址即ID1,它只是指向了这个list,并没有指向里面的元素。
决战Python之巅(六)---补充篇
决战Python之巅(六)---补充篇
如果从里面拿走一个元素,或者添加一个元素,那么L1,L2都会改变。实质上就是L1和L2都指向了一个杯子,往杯子里加一个枣或者减一个枣或者改变一个枣那么L1和L2里的元素都会改变,但是这个杯子还是这个杯子,就像你大爷还是你大爷,没变。这样应该能懂了吧。
然后是Copy, copy的意思就是复制。也就是说现在我有一个杯子L1,然后执行L2 = L1.copy(),就相当于我复制了一个杯子给L2,那么L1和L2现在是两个独立的杯子,也就是说他们指向了两个不同的内存地址:
决战Python之巅(六)---补充篇
现在我再将L1的第一个元素改变,L2还会跟着改变吗?
决战Python之巅(六)---补充篇
可以看到,现在就不会都改变了。你以为就这么简单??NO NO NO。我们再来看一下Copy过后list里元素的内存地址:
决战Python之巅(六)---补充篇
为啥这两个元素的内存地址是一样的捏?事实上,执行copy操作之后,你只将杯子复制了一个,但是杯子里的枣是两个杯子共享的,元素并没有copy。那么问题来了,既然是共享,那为什么L1改了之后,L2没变呢?我用一张图就能明白了:
决战Python之巅(六)---补充篇
很眼熟对吧,一开始L1[0]和L2[0]都指向了0(因为copy的原因),然后L1[0]改变了指向了999,但L2[0]指向的内存地址还是0,所以没有跟着改变。这就和a = 1,b = a, a = 2, b还是等于1一样,只不过b = a这句话的效果我们用copy完成了。

到这里…还没结束,给大家一个问题,大家思考下:
决战Python之巅(六)---补充篇
这里L2是多少呢?
决战Python之巅(六)---补充篇
那这里的L2又是多少呢?(敲一遍代码得到结果当然容易,但最好还是自己思考下为什么?)

———————————————————-默认你已经思考完了——————————————————————————-
第二次执行的结果,很意外,
决战Python之巅(六)---补充篇
L2竟然跟着L1变了,why???我们还是先看下内存地址:
决战Python之巅(六)---补充篇
2410125909896这个内存地址实际上指的是里面那个小列表的内存地址,就相当于大杯子里的一个小杯子的内存地址,二小杯子里的元素的内存地址还是独立的,这里就是我上面讲的那些,不懂的话可以翻回去看。也就是说,如果一个list中的某些元素也是list(列表是可以嵌套的),那么执行copy的话,也只是将小杯子的内存地址copy了一遍,他们都指向了同一个小杯子,里面的元素是共享的,所以前面的改了后面的也跟着变了,能理解了吧。
那如果,我现在要完完全全独立,里面的子列表我也想完全独立,现在这样的浅层copy就没办法实现。怎么办呢?既然有浅层的copy,那么肯定也会有深层次的copy啦:
决战Python之巅(六)---补充篇
这就相当于,现在我除了有两个大杯子,还有两个小杯子,而不再是两个大杯子都用一个小杯子。现在L1和L2是完全独立的,更改任何一个都不会影响到另一个。但是这个方法极少用,也劝大家不要用,为啥呢?假如说我现在有一个list,很大,大概有10个G,现在你deepcopy一下,这就有两个10G的list,也就是20G,非常占容量,所以还是少用为妙,除非迫不得已。

赞(0) 打赏
未经允许不得转载:老康的学习空间 » 决战Python之巅(六)---补充篇

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏