Python 缓冲机制是为提高程序执行的效率服务的,实际上就是在 Python 解释器启动时从内存空间中开辟出一小部分,用来存储高频使用的数据,这样可以大大减少高频使用的数据创建时申请内存和销毁时撤销内存的开销。
Python 在存储数据时,会根据数据的读取频繁程度以及内存占用情况来考虑,是否按照一定的规则将数据存储缓存中。那么问题来了,内存重用机制适用于哪些基本数据类型呢?
表 1 罗列了 Python 是否将指定数据存入缓存中的规则:
数据类型 | 是否可以重用 | 生效范围 |
---|---|---|
范围在 [-5, 256] 之间的小整数 | 如果之前在程序中创建过,就直接存入缓存,后续不再创建。 | 全局 |
bool 类型 | ||
字符串类型数据 | ||
大于 256 的整数 | 只要在本代码块内创建过,就直接缓存,后续不再创建。 | 本代码块 |
大于 0 的浮点型小数 | ||
小于 0 的浮点型小数 | 不进行缓存,每次都需要额外创建。 | |
小于 -5 的整数 |
下面直接通过一段程序来演示 Python 缓存机制的规则。
1. #范围在 [-5, 256] 之间的小整数
2. int1 = -5
3. int2 = -5
4. print("[-5, 256] 情况下的两个变量:", id(int1), id(int2))
6. #bool类型
7. bool1 = True
8. bool2 = True
9. print("bool类型情况下的两个变量:",id(bool1),id(bool2))
11. #对于字符串
12. s1 = "3344"
13. s2 = "3344"
14. print("字符串情况下的两个交量", id(s1), id(s2))
16. #大于 256 的整数
17. int3 = 257
18. int4 = 257
19. print("大于 256 的整数情况下的两个变量", id(int3), id(int4))
21. #大于 0 的浮点数
22. f1 = 256.4
23. f2 = 256.4
24. print("大于 0 的浮点数情况下的两个变量", id(f1), id(f2))
26. #小于 0 的浮点数
27. f3 = -2.45
28. f4 = -2.45
29. print("小于 0 的浮点数情况下的两个变量", id(f3), id(f4))
31. #小于 -5 的整数
32. n1 = -6
33. n2 = -6
34. 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 中有关变量缓存机制的规则。
同一代码块的缓存机制
在python中一个模块,一个函数,一个类,一个文件等都是一个代码块。
机制内容:Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存储在一个字典中,在遇到新的变量时,会先在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值。所以在你给出的例子中,文件执行时(同一个代码块)会把i1、i2两个变量指向同一个对象,满足缓存机制则他们在内存中只存在一个,即:id相同。
适用对象: int(float),str,bool。
对象的具体细则:(了解)
int(float):任何数字在同一代码块下都会复用。
bool:True和False在字典中会以1,0方式存在,并且复用。
str:几乎所有的字符串都会符合缓存机制,具体规定如下(了解即可!):
1,非乘法得到的字符串都满足代码块的缓存机制:
s1 = '太白@!#*ewq' s2 = '太白@!#*ewq' print(s1 is s2) # True
2,乘法得到的字符串分两种情况:
2.1 乘数为1时,任何字符串满足代码块的缓存机制:
b1 = '太白@5847395QQ0743895*&^%$#((&_+(())' *1 a1 = '太白@5847395QQ0743895*&^%$#((&_+(())' *1 print(a1 is b1) # True
2.2 乘数>=2时:仅含大小写字母,数字,下划线,总长度<=20,满足代码块的缓存机制:
s1 = 'old_' * 5 s2 = 'old_' * 5 print(s1 is s2) # True
优点:能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘字典’中取出复用,避免频繁的创建和销毁,提升效率,节约内存。
小数据池
小数据池,不同代码块的缓存机制,也称为小整数缓存机制,或者称为驻留机制等等
Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。
python会将一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。
其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将-5~256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中之创建一个。
适用对象: int(float),str,bool