每种编程语言都有一些不为人知的陷阱,有些实际工作中会踩到,有些可能根本排不上用场,但弄明白这些陷阱有利于我们更好的去了解这门语言的实现机制。
下面这道题,你是否能一眼看出问题的本质。
# 第一组
>>> a = 256
>>> b = 256
>>> a is b
True
# 第二组
>>> a = 257
>>> b = 257
>>> a is b
False
# 第三组
>>> a = 257; b = 257
>>> a is b
True
我们知道 is 函数比较的是两个对象的内存地址是否一样吗,id 函数返回一个和对象的内存地址相关的值)。言外之意,就是可以通过查看每个变量的 id 值来判断两个变量知否指向同一个对象。
PS:在 Python 的交互式命令行 REPL 中,每单独一行都视为一个代码块,同一行中的代码属于同一个代码块。因此不难理解,第三组中的a和b处在同一个代码块中,所以后者重用了前者,因此,两个变量的id是相同的。
科普知识
同样的,为了提高性能,Python 就把一些常用的整数专门缓存起来,就像屋子里面有些东西总是每天都要频繁使用,比如床,不能睡完之后就把床搬出去,要用了再搬回来,这样的效率太低了,因为整个搬运过程很耗时间的。于是,我们可以专门拿一块空间用来放置这个床。
Python 中也是同样的道理,因为整数是我们经常使用的对象,为了避免重复的创建、回收,干脆就把那些常用的整数缓存起来,每次需要使用时直接从缓存中拿,而不是重新创建(重新创建的话,肯定是一个全新的对象)。这些整数的范围是[-5, 256],当然这个数字范围是Python之父决定的,你要改,必须重新编译Python环境。
拓展案例
# test.py
# -*- coding: utf-8 -*-
a = 257
b = 257
def func():
c = 257
print(a is c) # False
print(a is b) # True
func()
上面代码是在一个 test.py 文件中,运行时,a和b的id值相同,而c的id值与a不一样,因为a、b 在同一个代码块,属于模块级别,而 c 是在函数里面,属于局部变量,他们不属于同一代码块中,因此函数里面的 257 这个对象时会重新创建,而创建 b 的时候,发现同级代码块中有个257的值了,就重用了这个对象。