目标
- 了解变量名与变量的关系
- 理解引用、拷贝、赋值等概念与含义
1 前提概况
我们接触最多的就是变量,究竟变量名
与 变量值
关系是啥?如何存储?
首先看一个最简单的
a = 100 |
上侧是一个赋值操作,其中a是变量名
,100是变量的值
。编程语言的编译器(或者解释器)处理到这一句代码的时候,一般语言会这样做
- 在内存中开辟一个内存空间, 地址0x4377878280;
- 存放100进第一步的空间中;
- 取值100时,找到地址为0x4377878280即可。
但是
但是
但是
这么长除了计算机能记住,我是记不住。正如ip地址与域名的关系,我们只需要记住taobao.com即可,所以,编译器给我们做了个表,在这个表中,它将内存地址和变量名做了个映射
变量名 | 内存地址 |
---|---|
a | 0x4377878280 |
b | 0x4377878281 |
c | 0x4377878282 |
… | …. |
变量名完全可以看成一个内存地址的别名(只是方便我们记忆),真正的数据是存在这个内存地址的存储空间上的。变量名在运行的时候,没有任何用处。
2. 深入一些
奔着:以问题来解决疑问题,先看这个代码,思考一下结果
0, 1, 2] values = [ |
请认真思考此时 values 是多少?
请认真思考此时 values 是多少?
请认真思考此时 values 是多少?
也许你认为是[0, [0, 1, 2], 2]
,原因可能是:
- list 可变;
- 把list[1]的位置直接添加一个list;
代码如下,完全符合预期
.
1, 2, 3] a = [ |
但是结果却是 无限循环
values |
❌就❎在第二步中
其中涉及两个概念:引用、拷贝
第一部分已经说过,变量名是内存的别称,
a=10
的含义:内存中有个地址0x1234567的空间存了10,然后a指向这块内存。
上图中很好的证明了,变量‘赋不同值’,只是引用不同而已
values[1] = values
只是把自身指向自身。如图:
如需达到预期效果,只需要类似于你的逻辑,指向一份值相同但内存不同的值
代码如下:
# 拷贝生成一份新的数据, |
往更深处说,values[:] 复制操作是所谓的「浅复制」(shallow copy),当列表对象有嵌套的时候也会产生出乎意料的错误,比如
a = [0, [1, 2], 3] |
看完上图的打印结果,请看下图;
重点: values[:] 只是浅层复制
重点: values[:] 只是浅层复制
重点: values[:] 只是浅层复制
正确的复制嵌套元素的方法是进行「深复制」(deep copy),方法是
import copy |
3 引用 VS 拷贝:
- 没有限制条件的分片表达式(L[:])能够复制序列,但此法只能浅层复制。
- 字典 copy 方法,D.copy() 能够复制字典,但此法只能浅层复制
- 有些内置函数,例如 list,能够生成拷贝 list(L)
- copy 标准库模块能够生成完整拷贝:deepcopy 本质上是递归 copy