• (转)实现一个cache装饰器,实现过期可清除功能


    原文:http://www.cnblogs.com/JerryZao/p/9574927.html

    http://blog.51cto.com/11281400/2107790-----装饰器应用练习

    文件私聊下载

      灵感来自

    from functools import lru_cache 的源代码,_make_key
    复制代码
      1 ''' 实现一个cache 装饰器,实现可过期被清除的功能'''
      2 
      3 # 第一步,实现了 与参数输入不同,也就是说,传入值后,
      4 # 不管什么样子,只要传入的顺序一样,结果一样,传入的值形成的 key 是一样的,这里用 {('x',4),('y',5)}
      5 ''' #通过sorted排序后,新进来的key 只要排序后 与前面的不同,就是不同的key
      6 add(4,5)
      7 add(x=4,y=5)
      8 add(4,y=5)
      9 add()
     10 -------输出的key都是一样的
     11 '''
     12 import inspect
     13 from functools import wraps
     14 import  time
     15 
     16 def cache(fn):
     17 
     18     @wraps(fn)
     19     def wrapper(*args, **kwargs):
     20         sig = inspect.signature(fn)
     21         params = sig.parameters
     22 
     23         values = list(params.values()) # 有序的
     24         keys = list(params.keys())
     25         print(values, keys)
     26 
     27         param_dic = {}
     28         #位置传参
     29         # for k, v in enumerate(args):
     30         #     param_dic[keys[k]] = v
     31         # 等价
     32         param_dic.update(zip(params.keys(), args))
     33         #关键字传参
     34         param_dic.update(kwargs)
     35         # 缺省值
     36         for k, v in params.items():
     37             if k not in param_dic:
     38                 param_dic[k] = v.default
     39         key = tuple(sorted(param_dic.items())) # sorted生成列表,不能做key,所以tuple一下
     40         print(key)
     41         return fn(*args, **kwargs)
     42     return wrapper
     43 
     44 @cache
     45 def add(x=4, y=5):
     46     return  x + y
     47 
     48 
     49 add(4,5)
     50 time.sleep(3)
     51 add(x=4,y=5)
     52 time.sleep(3)
     53 add(4,y=5)
     54 
     55 
     56 # 第二步,实现缓存
     57 import inspect
     58 from functools import wraps
     59 import  time
     60 
     61 def cache(fn):
     62     local_cache = {} # 对不同函数名是不同的cache
     63     @wraps(fn)
     64     def wrapper(*args, **kwargs):
     65         sig = inspect.signature(fn) # 获取签名 (x=4, y=5)
     66         params = sig.parameters # 获取参数字典,有序的 OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
     67 
     68         values = list(params.values()) # 有序的 [<Parameter "x=4">, <Parameter "y=5">]
     69         keys = list(params.keys())#   ['x', 'y']
     70 
     71         param_dic = {} # c参数字典
     72         #位置传参
     73         # for k, v in enumerate(args):
     74         #     param_dic[keys[k]] = v
     75         # 等价
     76         param_dic.update(zip(params.keys(), args)) # 二元组,放到字典中,形成 k-v对
     77         #关键字传参
     78         param_dic.update(kwargs) # 关键字参数,放到字典中
     79         # 缺省值
     80         for k, v in params.items(): # OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
     81             if k not in param_dic:
     82                 param_dic[k] = v.default
     83         key = tuple(sorted(param_dic.items())) # sorted生成列表,不能做key,所以tuple一下(key必须是可hash的,因为要用字典) (('x', 4), ('y', 5))
     84         # print(key)
     85         if key not in local_cache.keys():
     86             local_cache[key] = fn(*args, **kwargs)
     87         print(local_cache[key])
     88         return local_cache[key]
     89     return wrapper
     90 
     91 @cache
     92 def add(x=4, y=5):
     93     time.sleep(3)
     94     return  x + y
     95 
     96 add()
     97 add(4,5)
     98 add(4,y=5)
     99 
    100 # 第三步实现 清除缓存
    101 import inspect
    102 from functools import wraps
    103 import  time
    104 import datetime
    105 
    106 def cache(fn):
    107     local_cache = {} # 对不同函数名是不同的cache
    108     @wraps(fn)
    109     def wrapper(*args, **kwargs):
    110         # 清除缓存:注意:在对字典迭代的时候,是不能删除的!
    111         expire_keys = []
    112         # for k, v  in local_cache.items(): # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
    113         #     ret, stamp = v
    114         # 等价
    115         for k,(_,stamp) in local_cache.items():
    116             if datetime.datetime.now().timestamp() - stamp > 5:
    117                 expire_keys.append(k)
    118         for k in expire_keys:
    119             local_cache.pop(k)
    120         # 每次都要遍历,最好用线程,用的时候清除
    121 
    122 
    123         sig = inspect.signature(fn) # 获取签名 (x=4, y=5)
    124         params = sig.parameters # 获取参数字典,有序的 OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
    125 
    126         values = list(params.values()) # 有序的 [<Parameter "x=4">, <Parameter "y=5">]
    127         keys = list(params.keys())#   ['x', 'y']
    128 
    129         param_dic = {} # c参数字典
    130         #位置传参
    131         # for k, v in enumerate(args):
    132         #     param_dic[keys[k]] = v
    133         # 等价
    134         param_dic.update(zip(params.keys(), args)) # 二元组,放到字典中,形成 k-v对
    135         #关键字传参
    136         param_dic.update(kwargs) # 关键字参数,放到字典中
    137         # 缺省值
    138         for k, v in params.items(): # OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
    139             if k not in param_dic:
    140                 param_dic[k] = v.default
    141         key = tuple(sorted(param_dic.items())) # sorted生成列表,不能做key,所以tuple一下(key必须是可hash的,因为要用字典) (('x', 4), ('y', 5))
    142         # print(key)
    143         if key not in local_cache.keys():
    144             local_cache[key] = fn(*args, **kwargs), datetime.datetime.now().timestamp() # 放到二元组中,记录的是缓存的时间
    145             # 形成一个 {key:stamp}的字典
    146             #如果说到点清除,最好写结束时间,到点清除,记录一个未来时间
    147 
    148         print(local_cache) # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
    149         print(local_cache[key])
    150         return local_cache[key]
    151     return wrapper
    152 
    153 @cache
    154 def add(x=4, y=5):
    155     time.sleep(3)
    156     return  x + y
    157 
    158 add()
    159 add(4,5)
    160 add(4,y=5)
    161 
    162 # 第五步 优化:
    163 import inspect
    164 from functools import wraps
    165 import  time
    166 import datetime
    167 
    168 def logger(): #时间装饰器
    169     pass
    170 
    171 def cache(fn):
    172     local_cache = {} # 对不同函数名是不同的cache
    173     @wraps(fn)
    174     def wrapper(*args, **kwargs):
    175         def _clear_expire():
    176             ''' 优化1'''
    177             # 清除缓存:注意:在对字典迭代的时候,是不能删除的!
    178             expire_keys = []
    179             # for k, v  in local_cache.items(): # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
    180             #     ret, stamp = v
    181             # 等价
    182             for k,(_,stamp) in local_cache.items():
    183                 if datetime.datetime.now().timestamp() - stamp > 5:
    184                     expire_keys.append(k)
    185             for k in expire_keys:
    186                 local_cache.pop(k)
    187             # 每次都要遍历,最好用线程,用的时候清除
    188         def _make_key(args,kwargs):
    189             sig = inspect.signature(fn)  # 获取签名 (x=4, y=5)
    190             params = sig.parameters  # 获取参数字典,有序的 OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
    191             values = list(params.values())  # 有序的 [<Parameter "x=4">, <Parameter "y=5">]
    192             keys = list(params.keys())  # ['x', 'y']
    193             param_dic = {}  # c参数字典
    194             # 位置传参
    195             # for k, v in enumerate(args):
    196             #     param_dic[keys[k]] = v
    197             # 等价
    198             param_dic.update(zip(params.keys(), args))  # 二元组,放到字典中,形成 k-v对
    199             # 关键字传参
    200             param_dic.update(kwargs)  # 关键字参数,放到字典中
    201             # 缺省值
    202             for k, v in params.items():  # OrderedDict([('x', <Parameter "x=4">), ('y', <Parameter "y=5">)])
    203                 if k not in param_dic:
    204                     param_dic[k] = v.default
    205             key = tuple(sorted(param_dic.items()))  # sorted生成列表,不能做key,所以tuple一下(key必须是可hash的,因为要用字典) (('x', 4), ('y', 5))
    206             # print(key)
    207             return key
    208 
    209         _clear_expire()
    210 
    211         key = _make_key(args,kwargs)
    212 
    213         if key not in local_cache.keys():
    214             local_cache[key] = fn(*args, **kwargs), datetime.datetime.now().timestamp() # 放到二元组中,记录的是缓存的时间
    215             # 形成一个 {key:stamp}的字典
    216             #如果说到点清除,最好写结束时间,到点清除,记录一个未来时间
    217 
    218         print(local_cache) # {(('x', 4), ('y', 5)): (9, 1535638337.355427)}
    219         print(local_cache[key])
    220         return local_cache[key]
    221 
    222     return wrapper
    223 
    224 
    225 # 多装饰器,从下往上执行
    226 @logger
    227 @cache
    228 def add(x=4, y=5):
    229     time.sleep(3)
    230     return  x + y
    231 
    232 add()
    233 add(4,5)
    234 add(4,y=5)
    复制代码
    为什么要坚持,想一想当初!
  • 相关阅读:
    selenium操控浏览器
    DOM
    bug记录
    log日志
    linux 搭建 telnet + tftp
    linux 搭建 MeepoPS+Socket
    php常见面试题(2)
    php常见面试题(1)
    laravel 5 支付宝支付教程
    计算机进位制原理
  • 原文地址:https://www.cnblogs.com/liujiacai/p/9844948.html
Copyright © 2020-2023  润新知