1、本次实验环境:python
在腾讯云虚拟主机centos7上配置pyenv多版本python管理器,并安装交互式web编辑器jupyter,python版本为3.5.2。
2、装饰器:mysql
装饰器的本质是一个函数,接收一个函数做为参数,而且返回一个函数 带参数的装饰器是一个函数,返回一个装饰器 带参数的装饰器最多容许一层,timeit()()(不容许)
在python中,一个函数能够做为参数传递给另一个函数,还可返回一个函数(不了解此请看高阶函数)所以,咱们能够把一个函数传递给另外一个函数后,在这个被传递的函数的外部补充一些操做(装饰),然后把这个额外添加了补充装饰的函数得新return回来,装饰器也是高阶函数的一种。
一、不带参数的装饰器:web
#装饰器的本质是一个函数,接收一个函数做为参数,而且返回一个函数 #带参数的装饰器是一个函数,返回一个装饰器 #带参数的装饰器最多容许一层@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
二、带参数的装饰器:redis
#(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)
三、装饰器的应用:sql
(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)mongodb