嗯,最近打算从Java程序员转变为Python程序员,正所谓“人生苦短,我用Python”,突然间对Python对变量的管理感兴趣,于是就研究了一番,这里写篇文章记录一下Python变量的奥秘。
a = 1
b = 1
# id函数打印出内存地址
print(id(a))
print(id(b))
# 删除变量a
del a
# print(a) # 该语句会引发错误
# 打印b
print(b)
这里定义了两个变量a和b,值都为1。而id函数表示获取内存地址。del关键字则是删除变量a。我们看看运行结果。
140708927755936
140708927755936
1
从运行结果来看,a和b由于具备同样的值1,所以它们的内存地址相同。也就是a和b都指向了内存地址140708927755936。而我们在进行
del a
操作后,可以看到对应内存地址(140708927755936)的1被没有被删除,而是继续保留。那么应该怎么理解Python的变量呢?
其实在Python运行上述代码的时候,在没有执行
del a
之前它会创建一张变量表,来维护变量a和b的信息,如下表。
变量符号 | 指向内存地址 | 备注 |
a | 140708927755936 | 它会读取内存地址为140708927755936的值(1) |
b | 140708927755936 | 它会读取内存地址为140708927755936的值(1) |
这里需要注意的是Python解释器会根据变量表的变量符号获取内存地址,然后再从内存地址读取出数据。这样a和b都指向了相同的内存地址。我们把a和b称为对应内存地址(140708927755936)的引用。这个引用的概念,你可以理解为别名,比如你有个弟弟叫钱五,你可以叫他弟弟,也可以叫他五弟,或者直呼其名,而弟弟和五弟都是它的别名,都是指他这个人。同样的这里a和b都是内存地址(140708927755936)的值的别名。
当程序执行了:
del a
之后变量表又变了,它就变成了下面的样子。
变量符号 | 指向内存地址 | 备注 |
b | 140708927755936 | 它会读取内存地址为140708927755936的值(1) |
请注意这里删除的只是变量表中变量符号a,而不是地址140708927755936的值,所以a这个变量不能在Python上下文使用了。因此执行
print(a)
就会导致找不到变量名称而报错。而变量b依旧引用内存地址140708927755936的值,它并没有被删除,被删除的是变量表中a这个符号。
下面我们再测试下面代码。
a = 1
b = 1
# id函数打印出内存地址
print(id(a))
print(id(b))
# 修改变量b的值
b = 2
print(id(a))
print(id(b))
其运行结果为:
140708930639520
140708930639520
140708930639520
140708930639552
这里我们可以看到对a的值进行修改也会修改它的指向,在执行:
b = 2
之前,变量表示这样的。
变量表
变量符号 | 指向内存地址 | 备注 |
a | 140708930639520 | 它会读取内存地址为140708930639520的值(1) |
b | 140708930639520 | 它会读取内存地址为140708930639520的值(1) |
然后执行
b = 2
之后,变量表就变成了这样。
变量表
变量符号 | 指向内存地址 | 备注 |
a | 140708930639520 | 它会读取内存地址为140708930639520的值(1) |
b | 140708930639552 | 它会读取内存地址为140708930639552的值(2) |
注意到变量b,它指向的内存地址变化了,而a则不变。所以修改变量,只是修改了变量内存地址的指向,并不修改内存地址中的值,这里大家需要注意的地方。