(转)实现一个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来 ...
随机推荐
- lepus部署
lepus部署 lepus安装 cd /usr/local/src/lepus_v3.7/ cd python/ sh install.sh mysql配置 mysql -uroot -p'zaBBi ...
- BZOJ 3744 Gty的妹子序列 (分块 + BIT)
3744: Gty的妹子序列 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1931 Solved: 570[Submit][Status][Dis ...
- 微信小程序之跨界面传参
微信小程序在两个之间传参类似js传递url拼接参数,举个例子来说吧 input自己设置参数 //index.wxml <form bindsubmit="formSubmit" ...
- Oracle 数据库 dbConsole 配置笔记
Oracle安装后,DBConsole有时安装会失败,这时可以通过以下命令恢复: set oracle_sid=orclemca -repos recreateemca -config dbcontr ...
- DataGuard 配置须知
风不停,绿树荫,阳光晃眼,天真蓝,我们在奔跑,沿着斜阳,是你喘息,起伏不停... ——朴树 1.确认primary库处于归档模式 命令:archive log list; 如果没有启用归档,请先将数 ...
- Alpha阶段敏捷冲刺(八)
1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 祁泽文:写了关于统计的按钮的代码. 徐璐琳:完善了&q ...
- js加减运算·传参
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- 异步多线程 Task理解
一.简介 Task是.NET Framework4.0 TPL(任务并行库)提供的新的操作线程池线程的封装类.它提供等待.终止(取消).返回值.完成通知.失败通知.控制执行的先后次序等优化线程操作功能 ...
- [LintCode] Permutations
http://www.lintcode.com/en/problem/permutations/# Given a list of numbers, return all possible permu ...
- C# 对象转XML 支持匿名类
在网上找了很多关于对象转XML的,大多不支持匿名类转换,今天在stackoverflow找了一篇文章 但是有些许BUG 已经修复 public static class ObjectToXML { ...