原文: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. nginx负载均衡总结

    在关于高并发负载均衡一文中已经提到,企业在解决高并发问题时,一般有两个方向的处理策略,软件.硬件,硬件上添加负载均衡器分发大量请求,软件上可在高并发瓶颈处:数据库+web服务器两处添加解决方案,其中w ...

  2. Android拖动和缩放

    拖拽和缩放 多点触控的理论学完了之后,这里开始实践.本节主要介绍使用onTouchEvent()方法处理触控事件. 拖动一个对象 如果你使用的是Android 3.0或者之后的系统,那么你可以使用内置 ...

  3. C++指针二(易错模型)

    规则一:Main(主调函数)分配的内存(在堆区,栈区.全局区)都可以在被调用函数里使用.如果在被调用函数里面的临时区(栈)分配内存,主调用函数是不能使用的. #include "stdio. ...

  4. Qt_模块简介

    Qt4 和 Qt5最大的区别之一就是底层架构有了修改.Qt5引入了模块化的概念,讲众多功能细分到几个模块之中.需要达到,用什么模块知道到哪个模块去寻找. Qt5模块分为Essentials Modul ...

  5. 实用shell命令100条

    1,echo "aa" > test.txt 和 echo "bb" >> test.txt //>将原文件清空,并且内容写入到文件中, ...

  6. Hdu2204 Eddy's爱好 2017-06-27 16:11 43人阅读 评论(0) 收藏

    Eddy's爱好 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Subm ...

  7. 1.java面向对象编程三大特性之封装

    封装即把一个对象的属性.行为等放在一个实体类中隐藏起来,不允许外部对其进行修改,但是被封装的属性.行为会对外提供一个接口与外部联系,这个对外的接口通常情况下就是set().get()方法.可以通过se ...

  8. Oracle包被锁定的原因分析及解决方案

    http://blog.csdn.net/jojo52013145/article/details/7470812 在数据库的开发过程中,经常碰到包.存储过程.函数无法编译或编译时会导致PL/SQL ...

  9. DELPHI微信支付代码

    DELPHI微信支付代码   不管是微信支付还是支付宝支付, 3个最棘手的问题是:1,如何生成签名2,支付请求如何提交3, 如何验证签名 下面就围绕这二个问题来讲. 我使用的是XE3. 先看微信支付: ...

  10. SQL Server 阻塞原因分析

    这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype,open_tran,status,都是sysprocesses里的值,“ ...