标签:装饰器
一、本次实验环境:
在腾讯云虚拟主机centos7上配置pyenv多版本python管理器,并安装交互式web编辑器jupyter,python版本为3.5.2。
二、装饰器:
装饰器的本质是一个函数,接收一个函数作为参数,并且返回一个函数 带参数的装饰器是一个函数,返回一个装饰器 带参数的装饰器最多允许一层,timeit()()(不允许)
在python中,一个函数可以作为参数传递给另外一个函数,还可返回一个函数(不了解此请看高阶函数)因此,我们可以把一个函数传递给另一个函数后,在这个被传递的函数的外部补充一些操作(装饰),而后把这个额外添加了补充装饰的函数得新return回来,装饰器也是高阶函数的一种。
1、不带参数的装饰器:
#装饰器的本质是一个函数,接收一个函数作为参数,并且返回一个函数 #带参数的装饰器是一个函数,返回一个装饰器 #带参数的装饰器最多允许一层@timeit()()(不允许) #@abs #@all #@callable #def func(): # pass #abs(all(callable(func))) def fun(fn):#接收一函数作为参数 print(‘numner1‘) def wrap(*args,**kwargs):#接收函数的参数 print(‘number2‘) ret = fn(*args,**kwargs)#被装饰的函数 print(‘number3‘) return ret print(‘number4‘) return wrap @fun def func(*args,**kwargs): print(args) print(‘run‘) return args z = func(1,2,3,4,5,6) print(z) #等价于 def func(*args,**kwargs): print(args) print(‘run‘) return args z = fun(func) f = z(1,2,3,4,5,6) print(f) #等价于 def func(*args,**kwargs): print(args) print(‘run‘) return args z = fun(func)(1,2,3,4,5,6) print(z) print(‘############################################‘) #func被多个装饰器装饰 @fun @fun @fun def func(*args,**kwargs): print(args) print(‘run‘) return args z = func(1,2,3,4,5,6) print(z) #等价于 print(‘############################################‘) def func(*args,**kwargs): print(args) print(‘run‘) return args z = fun(fun(fun(func)))(1,2,3,4,5,6) print(z) #根据结果,先执行最外层函数与次内层函数的语句,然后执行次内层与次次内层的语句 #以此类推到最内层函数时,即为被装饰的函数func
2、带参数的装饰器:
#(1)、判断一个用户是否在允许列表中,若在,则执行fn功能函数 from functools import wraps def check(allows): def dec(fn): @wraps(fn)#这里的@wraps(fn)意思是装饰wrap函数,将fn作为参数, def wrap(username,*args,**kwargs):#此时函数wrap函数的方法(wrap.__name__等)即为fn.__name__ if username in allows: return fn(username,*args,**kwargs) return ‘not allow‘#抛出异常 return wrap return dec @check([‘i‘,‘you‘,‘he‘]) def test(username): print(‘congratulations‘) result = test(‘he‘) print(result) #等价于 def test(username): print(‘congratulations‘) result = check([‘i‘,‘you‘,‘he‘])(test)(‘she‘)#高阶函数理解了,这里也就多了一层函数,而这个函数接收了一个参数 print(result)
#(2)、default_user from functools import wraps def inject_user(default_user): def inject(fn): @wraps(fn) def wrap(*args,**kwargs): if ‘user‘ not in kwargs.keys(): kwargs[‘user‘] = default_user ret = fn(*args,**kwargs)#拿到我们想要的结果 return ret return wrap return inject @inject_user(‘comyn‘) def do_something(*args,**kwargs): print(kwargs.get(‘user‘)) return 23 ret = do_something(user=‘magedu‘) print(ret)
3、装饰器的应用:
(1)、装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能 (2)、装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景 (3)、装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用 (4)、概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
#(1)、cache缓存
import time
from functools import wraps
from functools import lru_cache#python内置的cache装饰器
def cache(instance):#instance为cache接口的封装
def dec(fn):
@wraps(fn)
def wrap(*args,**kwargs):
#key =>fn_name::params
pos = ‘,‘.join((str(x) for x in args))
kw = ‘,‘.join(‘{}={}‘.format(k,v) for k,v in sorted(kwargs.items()))
key = ‘{}::{}::{}‘.format(fn.__name__,pos,kw)#生成key
ret = instance.get(key)#判断key是否在cache中
print(key)
print(ret)
if ret is not None:#从cache中得到
return ret
ret = fn(*args,**kwargs)#这里我们也可以装饰一个到腾讯云mysql数据库取数据的函数
instance.set(key,ret)#放进缓存(这里指DictCache)
return ret
return wrap
return dec
class DictCache:#这里用一个字典来作为缓存,腾讯云缓存也可以
def __init__(self):
self.cache = dict()
def get(self,key):
return self.cache.get(key)
def set(self,key,value):
self.cache[key] = value
def __str__(self):
return str(self.cache)
def __repr__(self):
return repr(self.cache)
if __name__ == ‘__main__‘:
cache_instance = DictCache()#缓存实例可以是腾讯云memcached,redis,mongodb
@cache(cache_instance)
def long_time_fun(x):
time.sleep(x)
return x
x = long_time_fun(3)
print(x)
y = long_time_fun(3)
print(y)
#拿标准库来实现
@lru_cache()#具有换出策略lru
def time_fun(x):
time.sleep(x)
return x
x = time_fun(3)
print(x)
y = time_fun(3)
print(y)
#(2)、监控
import logging
import time
from functools import wraps
def mertic(prefix,instance):#instance为各种不同类型监控平台的对象,
def timeit(fn):# prefix为监控对象的前缀,属于哪个APP、主机的一个标记
@wraps(fn)
def wrap(*args,**kwargs):
start = time.time()
ret = fn(*args,**kwargs)#取数据
key = ‘{}.{}.{}‘.format(prefix,fn.__module__,fn.__name__)
instance.send(key,time.time()-start)#发送到监控处理的地方,比如statsd上
return ret
return wrap
return timeit
#influxdb,grafana展示
class LoggingMetric:
def send(self,key,value):
logging.warning(‘{}=>{}‘.format(key,value))
@mertic(prefix=‘mysql‘,instance=LoggingMetric())
def long_time_fun(x):
time.sleep(x)
return x
print(long_time_fun(1))
(3)、身份验证(4)、路由
未完待续!!!请看python3.5.2之装饰器(2)
本文出自 “11727697” 博客,请务必保留此出处http://11737697.blog.51cto.com/11727697/1834858
标签:装饰器
原文地址:http://11737697.blog.51cto.com/11727697/1834858