点评:下面的程序对实际开发并没有什么意义,但却是CPython中的一个大坑,这道题旨在考察面试者对官方的Python解释器到底了解到什么程度。
a, b, c, d = 1, 1, 1000, 1000 print(a is b, c is d) def foo(): e = 1000 f = 1000 print(e is f, e is d) g = 1 print(g is a) foo()
结果: True False True False True
上面代码中 a is b的结果是True但c is d的结果是False,这一点的确让人费解。这个结果是因为CPython出于性能优化的考虑,把频繁使用的整数对象用一个叫small_ints的对象池缓存起来造成的。
small_ints缓存的整数值被设定为[-5, 256]这个区间,也就是说,如果使用CPython解释器,在任何引用这些整数的地方,都不需要重新创建int对象,而是直接引用缓存池中的对象。
如果整数不在该范围内,那么即便两个整数的值相同,它们也是不同的对象。
CPython底层为了进一步提升性能还做了一个设定:对于同一个代码块中值不在small_ints缓存范围之内的整数,如果同一个代码块中已经存在一个值与其相同的整数对象,那么就直接引用该对象,否则创建新的int对象。
需要大家注意的是,这条规则对数值型适用,但对字符串则需要考虑字符串的长度,这一点可以自行证明。
扩展:如果你用PyPy(另一种Python解释器实现,支持JIT,对CPython的缺点进行了改良,在性能上优于CPython,但对三方库的支持略差)来运行上面的代码,你会发现所有的输出都是True。