原文: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)
为什么要坚持,想一想当初!