(转)实现一个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装饰器,实现过期可清除功能的更多相关文章
- 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...
- python 装饰器 (多个装饰器装饰一个函数---装饰器前套一个函数)
#带参数的装饰器 #500个函数 # import time # FLAGE = False # def timmer_out(flag): # def timmer(func): # def inn ...
- Python装饰器实现几类验证功能做法(续)
:昨天聊了一下构造.今天试了一下.感觉昨天聊的还是不够细化.今天结合代码实现,加以一点补充. 首先观察下面这个例子 from functools import wrapsdef decorator(f ...
- Python装饰器实现几类验证功能做法
最近新需求来了,要给系统增加几个资源权限.尽量减少代码的改动和程序的复杂程度.所以还是使用装饰器比较科学 之前用了一些登录验证的现成装饰器模块.然后仿写一些用户管理部分的权限装饰器.比如下面这种 de ...
- Python装饰器实现类Java注解功能
最近想用Python写一个简单生成器,类似指定类型和范围,返回指定列表: 比如想要 0 ~ 3 的整数,则 我只需要指定: 最小:0, 最大:3, 步长:1 则返回一个 [0,1,2,3] 的列表 ...
- 装饰器实现session登陆 验证功能
装饰器 登陆验证功能 1.装饰器模板 from django.shortcuts import render, redirect, HttpResponse from django.conf impo ...
- python 装饰器 第二步:扩展函数的功能(不修改原函数)
# 第二步:扩展函数的功能(不能修改原函数) # 用于扩展基本函数的函数 # 把一个函数(eat函数)作为一个整体传给另外一个函数(kuozhan函数) # 这个函数(kuozhan函数)用形参fun ...
- Python入门篇-装饰器
Python入门篇-装饰器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.装饰器概述 装饰器(无参) 它是一个函数 函数作为它的形参 返回值也是一个函数 可以使用@functi ...
- [原创]django+ldap实现单点登录(装饰器和缓存)
前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...
随机推荐
- c++关键字extern的作用
1.用extern修饰变量 使用在别的在源文件定义的非静态外部变量时,需要使用extern进行说明 2.用extern修饰函数 使用在别的在源文件定义的函数时,需要使用extern进行说明 3.用ex ...
- DDR中寄存器的问题
图中虚线是自动跳转,实线是通过发送命令才能跳转的. 下面是框中对应的命令. ACT = ACTIVATE MPR = Multipurpose register MRS = Mode register ...
- 20155205 2016-2017-2 《Java程序设计》第6周学习总结
20155205 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 在Java中,输入串流代表对象为Java.io.InputStream实例,输出串流 ...
- PAT甲级 1127. ZigZagging on a Tree (30)
1127. ZigZagging on a Tree (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...
- QT中的线程与事件循环理解(2)
1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不 ...
- 基于MATLAB的Sobel边缘检测算法实现
图像边缘就是图像灰度值突变的地方,也就是图像在该部分的像素值变化速度非常之快,就比如在坐标轴上一条曲线有刚开始的平滑突然来个大转弯,在变化出的导数非常大. Sobel算子主要用作边缘检测,它是一离散型 ...
- jvm虚拟机--堆内存
reserved 保留区域 堆 所有对象实例都在这里分配内存. 是垃圾收集的主要区域("GC 堆").现代的垃圾收集器基本都是采用分代收集算法,主要思想是针对不同的对象采取不同的垃 ...
- unigui 设置单元格颜色
procedure TF_Resource2.UniDBGrid1DrawColumnCell(Sender: TObject; ACol, ARow: Integer; Column: TUniD ...
- 如何在js里引用php变量
如何在js里面引用php的变量 php代码------------------------------------------- js代码------------------------------- ...
- Dacapao 实验集(9.12 版本) 能不能给个网址?【内存分析实验】
网址 Dacapao 实验集 引用 以前看到的文章,如果使用这个基准程序,引用文献很多时候是一篇论文: Blackburn S M, Garner R, Hoffmann C, et al. The ...