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

Posted liujiacai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(转)实现一个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)
复制代码

 

为什么要坚持,想一想当初!

以上是关于(转)实现一个cache装饰器,实现过期可清除功能的主要内容,如果未能解决你的问题,请参考以下文章

Python第五周 学习笔记

函数06装饰器的应用

假装优雅地实现定时缓存装饰器

实现有过期时间的LRU缓存

实现有过期时间的LRU缓存

一日一技:实现有过期时间的LRU缓存