原文: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装饰器,实现过期可清除功能的更多相关文章

  1. 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...

  2. python 装饰器 (多个装饰器装饰一个函数---装饰器前套一个函数)

    #带参数的装饰器 #500个函数 # import time # FLAGE = False # def timmer_out(flag): # def timmer(func): # def inn ...

  3. Python装饰器实现几类验证功能做法(续)

    :昨天聊了一下构造.今天试了一下.感觉昨天聊的还是不够细化.今天结合代码实现,加以一点补充. 首先观察下面这个例子 from functools import wrapsdef decorator(f ...

  4. Python装饰器实现几类验证功能做法

    最近新需求来了,要给系统增加几个资源权限.尽量减少代码的改动和程序的复杂程度.所以还是使用装饰器比较科学 之前用了一些登录验证的现成装饰器模块.然后仿写一些用户管理部分的权限装饰器.比如下面这种 de ...

  5. Python装饰器实现类Java注解功能

    最近想用Python写一个简单生成器,类似指定类型和范围,返回指定列表: 比如想要  0 ~ 3 的整数,则 我只需要指定: 最小:0, 最大:3, 步长:1 则返回一个 [0,1,2,3] 的列表 ...

  6. 装饰器实现session登陆 验证功能

    装饰器 登陆验证功能 1.装饰器模板 from django.shortcuts import render, redirect, HttpResponse from django.conf impo ...

  7. python 装饰器 第二步:扩展函数的功能(不修改原函数)

    # 第二步:扩展函数的功能(不能修改原函数) # 用于扩展基本函数的函数 # 把一个函数(eat函数)作为一个整体传给另外一个函数(kuozhan函数) # 这个函数(kuozhan函数)用形参fun ...

  8. Python入门篇-装饰器

    Python入门篇-装饰器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.装饰器概述 装饰器(无参) 它是一个函数 函数作为它的形参 返回值也是一个函数 可以使用@functi ...

  9. [原创]django+ldap实现单点登录(装饰器和缓存)

    前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...

随机推荐

  1. MFC连接MySQL

    其实,以前弄过sql,mysql应该是顺理成章很简单的事情,但很无奈,傻傻地弄了很久,还请教了别人,别人告诉我的跟我在网上查到的都是一样的,但还是不行,归根接地就是“mysql-connector-o ...

  2. vue2.0路由-路由嵌套

    vue一个重要的方面就是路由,下面是自己写的一个路由的例子: 1.引入依赖库就不必再说 2.创建组件 两种写法 第一种:间接 <template id="home"> ...

  3. hibernate映射组成关系

    目录结构 类 package com.hibernate.helloworld; public class School { private String name; private String a ...

  4. rhel5.4+oracle 10g rac

    各种报错各种愁啊 ... 1> 不知道什么原因,在节点2执行root.sh 报错 .无解 . 还原虚拟机,重新安装 .唯一与以前不同的是,执行orainroot.sh后 接着在节点2执行.再去分 ...

  5. (贪心 or DP)Woodcutters -- Codefor 545C

    http://codeforces.com/contest/545/problem/C  Woodcutters time limit per test 1 second memory limit p ...

  6. shell脚本-成长之路

    我对shell脚本的认识,除了执行过同事写的shell 脚本外,其他一无所知,为了让自己强大,我决定自己研究shell脚本,也许在你看来很简答,没必要说这么多废话,但是我希望在我的技术log里记录下来 ...

  7. Android listview 侧滑 SwipeListView 详解 实现微信,QQ等滑动删除效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/28508769 今天看别人项目,看到别人使用了SwipeListView,Goog ...

  8. html5 定位

    需要实现的功能:移动端的网页,能定位到中文地址. 百度地图能实现这样的功能. 之前精度差得原因是,我用自己的mac做服务器,用手机来浏览定位,这样只能定位到mac 的地址,mac上浏览器的地址就没准了 ...

  9. how can I make the login form transparent?

    This is how you can make the Login Form transparent: 1. Add this css to Server Module-> Custom cs ...

  10. acdream 20140730 D题

    今天见识到了“数学上来先打表”............ #include<iostream> using namespace std; #include<iomanip> #d ...