缓存装饰器练习

本文介绍如何实现一个具备过期和清除功能的缓存装饰器,模仿Python的`lru_cache`。装饰器使用字典存储缓存,通过时间戳判断过期,并确保生成的key为可哈希。关键在于正确处理位置参数、关键字参数和缺省参数,构造排序后的key。首先完成基础功能,然后利用`inspect`模块获取函数参数,设置超时,并进行代码优化,追求结构化和整洁。

题目:

实现一个cache装饰器,实现可过期,可清除的功能,可以不换出(模仿lru_cache)

  • 思路:

    • cache缓存装饰器,是有key值的---------->可得到用字典类型

    • 过期指的是key值过期,过期是一定时间,可以用时间戳来做对比

    • 最重要的是key值的生成,且key一定是可hash的,key可以接受位置参数,关键字参数,缺省参数

      • 而位置参数解构之后是tuple

      • 关键字参数解构得到dict类型,而字典是无序的。传参的顺序不一定是字典中保存的顺序

      • 故而得到key之后要排序下。

  • 1.先把基础功能写下来

    • 先把装饰器结构写出来

    • def pr_cache(fn):
          def warpper(*args,**kwargs):
              ret = fn(*args,**kwargs)
              return ret
          return warpper

    • 先写key的构造

    • inspect模块的signature函数,可以获取函数的所有参数

    • default

      • 获得函数的关键字参数的值

      • import inspect
        import functools
        
        def pr_cache(fn):
            @wraps(fn)
            def warpper(*args,**kwargs):
                dict_key = {}
        
                od = inspect.signature(fn)
                ####有序字典
                od_dict = od.parameters
        	    od_list = list(od_dict.keys())
                
                ####位置参数
                for i, v in enumerate(args):
                    k = od_list[i]
                    dict_key[k] = v
        
                ####关键字参数
                dict_key.update(kwargs)
        
                ####缺省参数
                for k in od_dict.keys():
                    if k not in dict_key.keys():
                        dict_key[k] = od_dict[k].default
        
                key = tuple(sorted(dict_key.items()))
        
                if key not in dict_key.keys():
                    ret = fn(*args, **kwargs)
                    dict_key[key] = ret
        
                return dict_key[key]
            return warpper

         

  • 超时的设置:代码如下
  • import inspect
    import functools
    import datetime
    
    def pr_cache(fn):
        dict_cache = {}
        def warpper(*args,**kwargs):
            ts_list = []
            for i, (_,ts) in dict_cache.items():
                if datetime.datetime.now().timestamp() - ts > 5:
                    ts_list.append(i)
            for k in ts_list:
                dict_cache.pop(k)
    
            dict_key = {}
            od = inspect.signature(fn)
            ####有序字典
            od_dict = od.parameters
    
            od_list = list(od_dict.keys())
    
            ####位置参数
            for i, v in enumerate(args):
                k = od_list[i]
                dict_key[k] = v
    
            ####关键字参数
            dict_key.update(kwargs)
    
            ####缺省参数
            for k in od_dict.keys():
                if k not in dict_key.keys():
                    dict_key[k] = od_dict[k].default
    
            key = tuple(sorted(dict_key.items()))
    
            if key not in dict_cache.keys():
                ret = fn(*args, **kwargs)
                dict_cache[key] = (ret, datetime.datetime.now().timestamp())
    
            return dict_cache[key]
        return warpper
    @pr_cache
    def add(x,y=5):
        ret = x + y
        time.sleep(5)
        print(ret)
        return ret
    
    print(add(4,5))
    #print(add(4))
    time.sleep(5)
    print(add(4,y=5))
    print(add(x=4,y=5))
    print(add(y=5,x=4))

    函数的功能做出来了,测试没问题

  • 但是代码还可以在整理,封装下

    • 不会为了复用,而是整洁,结构化

  • 代码如下

    import inspect
    import functools
    import datetime
    def o_cache(overtime):
        def pr_cache(fn):
            dict_cache = {}
            def warpper(*args,**kwargs):
                def over_time(over_cache):
                    ts_list = []
                    for i, (_,ts) in over_cache.items():
                        if datetime.datetime.now().timestamp() - ts > overtime:
                            ts_list.append(i)
                    for k in ts_list:
                        over_cache.pop(k)
                over_time(dict_cache)
    
                def make_key(fn):
                    dict_key = {}
                    od = inspect.signature(fn)
                    ####有序字典
                    od_dict = od.parameters
    
                    od_list = list(od_dict.keys())
    
                    ####位置参数
                    for i, v in enumerate(args):
                        k = od_list[i]
                        dict_key[k] = v
    
                    ####关键字参数
                    dict_key.update(kwargs)
    
                    ####缺省参数
                    for k in od_dict.keys():
                        if k not in dict_key.keys():
                            dict_key[k] = od_dict[k].default
    
                    return tuple(sorted(dict_key.items()))
                key = make_key(fn)
                if key not in dict_cache.keys():
                    ret = fn(*args, **kwargs)
                    dict_cache[key] = (ret, datetime.datetime.now().timestamp())
    
                return dict_cache[key]
            return warpper
        return pr_cache
    @o_cache(5)
    def add(x,y=5):
        ret = x + y
        time.sleep(3)
        print(ret)
        return ret
    
    print(add(4,5))
    print(add(4))
    time.sleep(5)
    print(add(4,y=5))
    print(add(x=4,y=5))
    print(add(y=5,x=4))

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值