python的缓存机制

  • 前言
  • id()函数
  • 实例测试



前言

因为在创建数据时需要为数据创建内存,在销毁数据时需要释放内存,为了提高效率,Python使用了缓存机制。
什么是缓存机制呢?就是Python将一些值预先存好,当定义一个变量,并给他赋值时,会先匹配这些缓存好的值,如果有匹配的话,就将变量指向对应的内存。
那Python是不是将所有的值都预先存好了呢?显然是不可能的。在Python解释器启动时从内存空间中开辟出一小部分将一些比较常用的值预先定义好。
那今天我们就来了解一下,都有哪些预先存好的值。

id()函数

在进入正题之前,我们先了解一下id()函数:

id() 函数返回对象的唯一标识符,标识符是一个整数。
对应的内存地址是hex(id)

print(id(11), id("string"))

python 文件缓冲区 python缓存数据_Python

实例测试

先试试一个较小的值:

a = 11
b = 11

print(a is b)
print(id(a), id(b))

python 文件缓冲区 python缓存数据_python_02


a和b的id值都是相同的,很显然他们指向了同一个内存地址。


再试试一个较大的值

c = 500
d = 500

print(c is d)
print(id(c), id(d))

python 文件缓冲区 python缓存数据_python 文件缓冲区_03


当值为500时,id值已然不同。


我们用一个循环来看看具体有哪些值:

for num1, num2 in zip(range(-10, 500), range(-10, 500)):
    if id(num1) == id(num2):
        print(num1, end="\t")

python 文件缓冲区 python缓存数据_字符串_04


由上可知预定义的值为 [-5, 256]


但是我还是有疑问,会不会是range()函数在搞鬼呢?

for num3 in range(-10, 500):
    if num3 == 11:
        print(id(num3) == id(11))

python 文件缓冲区 python缓存数据_python_05


上面的例子都是int型的数据,那么boolstr类型的数据呢?
先试试bool

bool1 = True
bool2 = True

print(id(bool1), id(bool2))

python 文件缓冲区 python缓存数据_列表_06


bool值的id也是一样的


接下来是str

str1 = "aaa"
str2 = "aaa"
print(id(str1), id(str2))

python 文件缓冲区 python缓存数据_python 文件缓冲区_07


这里的id也是相同的,但是这个值是我随意写的,不可能说Python解释器启动的时候就将这些值定好了吧?唯一合理的解释就是,我定义了str1之后,再定义str2时,会去检索是否已经定义过,如果已经定义,那么就将str2指向其地址。


那么怎么确定 **[-5, 256]**是一开始就创建好的呢?
我们反复运行开头的哪行代码,发现不管运行几次,都是相同的结果,

print(id(11), id("string"))

python 文件缓冲区 python缓存数据_Python_08


但是,如果重启运行时,

python 文件缓冲区 python缓存数据_列表_09


python 文件缓冲区 python缓存数据_字符串_10

再运行,就会发现id(11)的值跟之前的是一样的,而id("string")的值跟之前不一样了,再继续运行时,则不会再变了。


如果是List(列表)、Tuple(元组)、Dictionary(字典)等数据类型的值呢?

list1 = [2, 2, 257]
list2 = [2, 257, 257]
print("2: ", id(list1[0]), id(list1[1]), id(list2[0]))
print("257:", id(list2[1]), id(list2[2]), id(list1[2]))
print("\n")

tuple1 = (2, 2, 257)
tuple2 = (2, 257, 257)
print("2: ", id(tuple1[0]), id(tuple1[1]), id(tuple2[0]))
print("257:", id(tuple2[1]), id(tuple2[2]), id(tuple1[2]))

python 文件缓冲区 python缓存数据_python 文件缓冲区_11


对于257,list1和list2的257id的值是不同的,而同在list2中的257的id的值却是相同的;tuple中也是同样的;

对于整数2,不管是list1,list2,还是tuple1, tuple2的id的值都是相同的。

dict1 = {"a1": 2, 
         "a2": 2, 
         "a3": 257,
         2: "abc"
        }
dict2 = {"a1": 257, 
         "a2": 257, 
         "a3": 2,
         257: "abc"
        }
print("2:", id(dict1["a1"]), id(dict1["a2"]), id(dict2["a3"]))
print("\nstr key:")
for i in dict1.keys():
    print(id(i))
print("\n")
print("257:", id(dict2["a1"]), id(dict2["a2"]), id(dict1["a3"]))
print("\nstr key:")
for i in dict2.keys():
    print(id(i))
print("\nabc: ", id(dict1[2]), id(dict2[257]))

python 文件缓冲区 python缓存数据_字符串_12


对于整数2,在dict1和dict2中不管是作为键还是值,id都是相同的;

对于整数257, id(dict2[“a1”])和id(dict2[“a2”])的值相同,但与id(dict1[“a3”])不同;

对于字符串,在dict1和dict2中不管是作为键还是值,id都是相同的。


那要是在不同的作用域呢?

int1, int2 = 2, 257
str1 = "abcd"

def func():
    int3, int4 = 2, 257
    print("id(int1) == id(int3):", \
          id(int1) == id(int3),\
          "\nid(int2) == id(int4):",\
          id(int2) == id(int4))
    str2 = "abcd"
    print("id(str1) == id(str2):", id(str1) == id(str2))
    
func()

python 文件缓冲区 python缓存数据_Python_13


由此可见,预先定义的值是全局的,字符串也是全局的


下面这个图从参考链接而来,但是小数部分却得出了不同的结果:

python 文件缓冲区 python缓存数据_Python_14