from functools import wraps
import inspect
import datetime
def cache(exp=0): #超时0 也就是没有超时时间
def _cache(fn):
c = {} #把结果存放到cache里面,用来存储我们的缓存
@wraps(fn)
def wrap(*args,**kwargs):
#1 key 如何封装args kwargs
print (args)
print (kwargs)
key=[ ] #初始化是空值
names=set() #name 需要加入,args 和kwargs的name 要做修改,names 作为key避免重复用set()
params = inspect.signature(fn).parameters #获取所有的参数,获取后第一步,参数列表
#args 操作
for i ,arg in enumerate(args): #args是元祖 arg 是value,那么name是什么?args 是位置参数
#value 和params 取出的值是一样的。 args 是位置参数,所以他的顺序和params 顺序是一致的
name = list(params.keys())[i]#获取所有的key 通过下标i去访问,返回x或y
# ,name是我们的key
key.append((name,arg)) #把元祖丢进去 key====>[(x,1),(y,2)]
names.add(name) #把上面的name丢进去
#kwargs操作
#for k,v in kwargs.items():
# key.append((k,v))
#更简单办法
key.extend(kwargs.items()) #key 已经封装了
names.update(kwargs.keys()) #kwargs的names更新了
for k,v in params.items(): #之前的params的list params是整个函数的参数列表
#如何获取默认参数,
#***如果定义函数的时候,有默认参数,在传参的时候没有传这个默认参数,我们就拿不到它
#params是整个函数的参数列表
#判断params里不在names里的 就是默认参数
if k not in names:
key.append((k,v.default))
#排序 key是列表,列表有个方法key.sort、 sort参数有个key用于传fan,x就是指key里面每个迭代对象
#x 可能是[(x,1),(y,2)]里面的(x,1) 或 (y,2)元祖,按照每个列表里面每一个元素的第一个排序,也就是key排序
key.sort(key=lambda x:x[0])
#key 排序后进行封装,用& join 列表解释式做
key = '&'.join([ f'{name}={arg}'for name,arg in key]) #for name,args in key j解构
print (key)
#命中监测
if key in c.keys():
# 超时监测
#如何判断一组key 什么时候执行过呢
#key &ts=2222233,还有一种,
#key=(key,timestamp):values 用这个 用参数解构
ret,timestamp =c[key] #拿到结果里面 有timestap 接收
if exp==0 or datetime.datetime.now().timestamp() - timestamp< exp: #满足命中缓存的添加的输出结果
print(f'命中缓存:{key}:{args},{kwargs}')
return c[key]
#2 超时监测
#最后拿到结果 ret = fn(*args,**kwargs)
ret = fn(*args,**kwargs)
print('缓存未命中')
c[key] = (ret,datetime.datetime.now().timestamp()) #元祖
return ret
return wrap
return _cache
![]()