大家好,欢迎来到 Crossin的编程教室 !
上一次,我们聊了点关于 Python 中变量的基础知识点。今天继续这个话题聊下去。
1. 变量的赋值
之前说到,Python 中的「赋值」操作符就是一个等号(=)。通过赋值操作可以创建一个变量,也可以修改一个变量的已有值。
那有人就要说了:
为什么 a = 1 可以赋值,1 = a 就会报错?这不都是一个等式吗?
这是因为 Python 的赋值操作符(=)并不等同于数学中的等式。数学中等式满足交换律,左右两边互换没有问题。但编程中的赋值是有方向的,是把等号右边的结果赋值给左边的变量。
理解了赋值的方向性,很多语法就好理解了:
代码语言:javascript复制a = 1
就是把右边的数值1赋值给左边的变量a,这没毛病。
代码语言:javascript复制1 = a
右边是变量a的值这没问题,但左边被赋值的是一个数值,这就不行了,所以报错。❌
因为是把右边的“结果”赋值给左边的变量,所以右边不仅可以是一个固定值,也可以是个计算式:
代码语言:javascript复制a = 1 2 * 3 ** 4 / 5
这个计算式里也可以含有变量:
代码语言:javascript复制b = 3
a = b * 2 3
甚至可以带有函数,只要保证计算式本身是可执行的就行:
代码语言:javascript复制a = input() 'abc'
于是,被赋值的变量本身也可以作为右边计算式的一部分:
代码语言:javascript复制a = 2
a = a 1
这个式子以数学的眼光来看显然是不成立,但在编程中非常常见,作用就是把变量 a 的值增加 1。
它还有个简化写法:
代码语言:javascript复制a = 1
类似还有 -=、*=、/=、%=、//= 等等。
如果你学过 C ,应该知道这种变量自增 1 的语句还有种更简化的写法:
代码语言:javascript复制a
但不好意思,这里是 Python,不能这么写。❌
至于数学中的等式,Python 更接近的比较运算符(==),比如:
代码语言:javascript复制a == 1
2 == a
1 3 == a 3
用来判断(==)左右两边的计算结果是否相等,结果是 True 或者 False。这个我们下回再来细说。
2. Python 变量不是一个「容器」
接下来讲的这点有一点点进阶。
很多人在了解的变量的使用之后,可能会把变量想象一个装数据的「容器」,就好比一个杯子,赋值就是往里面倒饮料,重新赋值就是倒上其他的饮料。
这种理解在 C 这样的语言里是没有问题的。也正因为如此,C 才需要在使用前「定义」变量,确定类型,程序也会分配好对应的内存空间。
但可惜,在 Python 里这个理解是错误的。❌
Python 里的变量,与其说是装数据的容器,倒不如说是贴在数据上的标签。
变量并不占用空间,占用空间的是数据本身。当你重新赋值时,就相当于撕下这个标签,贴纸另一个数据上。
Python 中所有东西都是对象,包括函数、类、模块,甚至是字符串’hello’,数字1、2、3,都是对象。
用个例子来说明:
代码语言:javascript复制a = 1
b = 2
c = 1
# 再次赋值
a = b
在这个代码里,a 和 c 其实指向的是同一个对象—整数 1。给 a 赋值为 b 之后,a 就变成了指向 2 的标签,但 1 和 c 都不会受影响。
示意图:
更有说服力一点的验证:
代码语言:javascript复制a = 1
print('a', a, id(a))
b = 2
print('b', b, id(b))
c = 1
print('c', c, id(c))
# 再次赋值
a = b
print('a', a, id(a))
输出:
代码语言:javascript复制a 1 4301490544
b 2 4301490576
c 1 4301490544
a 2 4301490576
id() 可以认为是获取一个对象的地址。可以看出,a 和 c 开始其实是同一个地址,而后来赋值之后,a 又和 b 是同一个地址。
每次给变量重新赋值,它就指向了新的地址,与原来的地址无关了。
关于这方面的详细解释,可以参考之前的几篇文章:
- Python到底是引用传递还是值传递?网上大多数教程都讲错了
- 继续打脸水货教程:关于可变对象与不可变对象
对于 Python 的变量赋值,你还要什么想了解的内容?欢迎在留言区讨论。
_往期文章推荐_
Python变量基础