在那个世界里头, 性能优化可不是仅仅靠着开发者写出高效代码就行的。用 C 语言实现的那个解释器, 它的那个最为常用的版本, 在底层针对常见对象做了精巧的缓存优化。这些优化的办法, 不但使得性能得以提高, 而且还把内存占用给减少了。
一、小整数缓存机制
启动的时候, 会预先去创建, 并且缓存处于 -5 到 256 范围之内的整数对象。这些对象在整个运行的期间都是单例, 这意味着当多个变量引用它们的时候, 会去共享同一块内存。
a = 100
b = 100
print(a is b) # True
为什么会是这个范围呢, 这主要是基于性能方面的考虑, 小整数在实际运用当中会频繁地出现, 像是循环计数、列表索引、状态标识等情况, 缓存能够显著地提升执行效率。
源码(/.c)中定义如下:
#define NSMALLPOSINTS 257 // 0 到 256
#define NSMALLNEGINTS 5 // -1 到 -5
是针对超出这个范围的那些整数而言的 , 像1000这样的 , 每次所创建的对象是不一样的 , 是有区别的 , 是各不相同的:
a = 1000
b = 1000
print(a is b) # False(通常)
注意:
一些(像交互式解释器、控制台这样的)解释器, 有可能因常量合并优化, 致使 a is b 变为 True, 这并非标准行为, 不能予以依赖。
二、字符串驻留机制
对一部分字符串开展了缓存操作, 这被称为"字符串驻留"()。要是多个变量所持有乃是同一个驻留字符串, 那么它们将会实现内存地址的共享。
哪些字符串会被驻留:
1、那些长度是 0 或者 1 的字符串, 像: ""(此为空字符串)、"a"(这是单字符字符串)等等。
2、仅由字母、数字以及下划线所构成的标识符样式字符串, 也就是合法的变量名样式, 像这种, 比如: "hello"、"var_1" 等等等等这类的。
标识符样式字符串是在编译阶段自动驻留的。
3、显式调用 sys.() 的字符。
a = "hello" # 标识符样式字符串
b = "hello"
print(a is b) # True (被驻留)
a = "hello world" #含空格或标点的字符串
b = "hello world"
print(a is b) # False(不是合法的变量名样式,也可能被解释器优化,结果为 True)
a = "a" # 单字符字符串
b = "a"
print(a is b) # True(长度为 1)
可以使用 sys.() 手动强制驻留字符串:
import sys
a = sys.intern("hello world")
b = sys.intern("hello world")
print(a is b) # True
提示:
字符串驻留的行为在不同 版本之间有所不同,不能完全依赖。
三、单例对象的共享

嵌入了几个在全局范围内独一无二的单例对象, 并在内存里仅仅存在个别一份, 且在整个程序进程中进行再度使用且不间断。
None,空值。
True / False,布尔值。
有着内置对象, 其类型是这样的这般, 常常被用作占位符, 或者是切片里的简略表示形式, 是这样的情况。
,用于算术操作不支持时的返回值。
a = None
b = None
print(a is b) # True
a = ...
b = ...
print(a is b) # True
这些对象在 启动时就已经创建,并且始终只存在一份。
四、空的不可变容器缓存
还缓存了某些空的不可变对象,例如:
a = ()
b = ()
print(a is b) # True 因为空元组是缓存的
a = ""
b = ""
print(a is b) # True 空字符串也是缓存的
这同样是一种用于内存优化的办法, 鉴于空的不能改变的对象时常会出现, 所以是能够共同分享去使用的。
要的注意的是,可变对象不会缓存:
print([] is []) # False
print({} is {}) # False
五、补充说明
1、不要把、套用在、关于空元组(())行为, 空的 () 不会被缓存, 就算内容一样每次创建的对象与先前不同。
a = frozenset()
b = frozenset()
print(a is b) # False
在早期的时候, 于某些版本当中, 或者是交互式解释器里面, 存在着这样一种可能性, 那就是会因为编译器进行优化从而出现缓存的效果, 然而这并不是规范所规定的行为, 并且是不可靠的。
2、不要滥用 is 来比较值
对象身份的判断, 使用的是is, , 而不是比较值, , 比较数值的时候, 应该使用的是==。
# 正确
if a == 1000:
...
# 不推荐
if a is 1000:
...
正确场景是使用is的情况为: 去比较单例对象, 像None、True、False这些。