Python 缓冲机制是为提高程序执行的效率服务的,实际上就是在 Python 解释器启动时从内存空间中开辟出一小部分,用来存储高频使用的数据,这样可以大大减少高频使用的数据创建时申请内存和销毁时撤销内存的开销。

Python 在存储数据时,会根据数据的读取频繁程度以及内存占用情况来考虑,是否按照一定的规则将数据存储缓存中。那么问题来了,内存重用机制适用于哪些基本数据类型呢?

表 1 罗列了 Python 是否将指定数据存入缓存中的规则:

表 1 Python 缓存重用规则
数据类型是否可以重用生效范围
范围在 [-5, 256] 之间的小整数如果之前在程序中创建过,就直接存入缓存,后续不再创建。全局
bool 类型
字符串类型数据
大于 256 的整数只要在本代码块内创建过,就直接缓存,后续不再创建。本代码块
大于 0 的浮点型小数
小于 0 的浮点型小数不进行缓存,每次都需要额外创建。
小于 -5 的整数

 
下面直接通过一段程序来演示 Python 缓存机制的规则:

#范围在 [-5, 256] 之间的小整数
int1 = -5
int2 = -5
print("[-5, 256] 情况下的两个变量:", id(int1), id(int2))

#bool类型
bool1 = True
bool2 = True
print("bool类型情况下的两个变量:",id(bool1),id(bool2))

#对于字符串
s1 = "3344"
s2 = "3344"
print("字符串情况下的两个交量", id(s1), id(s2))

#大于 256 的整数
int3 = 257
int4 = 257
print("大于 256 的整数情况下的两个变量", id(int3), id(int4))

#大于 0 的浮点数
f1 = 256.4
f2 = 256.4
print("大于 0 的浮点数情况下的两个变量", id(f1), id(f2))

#小于 0 的浮点数
f3 = -2.45
f4 = -2.45
print("小于 0 的浮点数情况下的两个变量", id(f3), id(f4))

#小于 -5 的整数
n1 = -6
n2 = -6
print("小于 -5 的整数情况下的两个变量", id(n1), id(n2))

注意,此程序中,大量使用 id() 内置函数,该函数的功能是获取变量(对象)所在的内存地址。运行该程序,其输出结果为:

[-5, 256] 情况下的两个变量: 1792722416 1792722416
bool类型情况下的两个变量: 1792241888 1792241888
字符串情况下的两个交量 2912801330712 2912801330712
大于 256 的整数情况下的两个变量 2912801267920 2912801267920
大于 0 的浮点数情况下的两个变量 2912762210728 2912762210728
小于 0 的浮点数情况下的两个变量 2912762211016 2912762211040
小于 -5 的整数情况下的两个变量 2912801267952 2912801267984

以上输出结果中,每行都输出了 2 个相对应的变量所在的内存地址,如果相等,则表明 Python 内部对其使用了缓存机制,反之则没有。读者可对照以上输出结果来理解表 1 中有关变量缓存机制的规则。

另外,对于表 1 中所提到的代码块,Python 中的函数和类都被认为是在程序中开辟了一块新的代码块。以函数为例,函数内部的代码分属一个代码块,函数外部的代码属于另一个代码块。

有关函数的具有用法,后续章节会详细介绍,这里读者只需要知道函数中包含的代码,属于一个新的代码块即可。

由表 1 可以看到,Python 缓存机制在不同的代码块中也会有不同的表现。举一个例子,在上面例子代码的基础上,继续编写如下程序:

def fun():
    #[-5,256]
    int1 = -5
    print("fun中 -5 的存储状态",id(int1), id(int2))
    
    #bool类型
    bool3 = True
    print("fun中 bool 类型的存储状态",id(bool3),id(bool2))
    
    #字符串类型
    s1 = "3344"
    print("fun 中 3344 字符串的存储状态", id(s1), id(s2))

    #大于 256
    int3 = 257
    print("fun中 257 的存储状态", id(int3), id(int4))

    #浮点类型
    f1 = 256.4
    print("fun 中 256.4 的存储状态",id(f1), id(f2))

    #小于 -5
    n1 = -6
    print("fun 中 -6 的存储状态", id(n1), id(n2))
   
fun()

输出结果为:

fun中 -5 的存储状态 1792722416 1792722416
fun中 bool 类型的存储状态 1792241888 1792241888
fun 中 3344 字符串的存储状态 1976405206496 1976405206496
fun中 257 的存储状态 1976405225648 1976405225680
fun 中 256.4 的存储状态 1976394459752 1976394459872
fun 中 -6 的存储状态 1976404744880 1976405225744

根据输出结果可以分析出:

1、从 -5 、bool 类型以及字符串 "3344" 的输出结果可以得知,无论是在同一代码块,还是不同的代码块,它们都使用相同的缓存内容;

2、从 257 和 256.4 的输出结果可以得知,如果位于同一代码块,则使用相同的缓存内容;反之,则不使用;

3、从 -6 的输出结果得知,Python 没有对其缓存进行操作。