装饰器的介绍
什么是装饰器
“装饰”指的是为被装饰对象添加新的功能,“器”指的是工具。
装饰器指的是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能
为何要用装饰器
# 开放封闭原则 开放:对扩展是开放的(可以添加新的功能) 封闭:对修改是封闭的(不能修改源代码和调用方式) 装饰器就是在不修改被装饰对象源代码和调用函数的前提下为被装饰对象添加额外的功能
装饰器的实现
装饰器分为无参装饰器和有参装饰器,二者的实现原理都是 函数嵌套+闭包函数+函数对象 组合使用的产物
无参装饰器
无参装饰器的模板
def outter(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
无参装饰器的推导
需求:在不修改index函数的源代码及调用方式的前提下为其添加统计运行时间的功能
# 源代码及其调用方式 import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 index(111,y=222)
# 解决方案一 # 没有修改被装饰对象的源代码,没有修改改变方式,并且增加了新功能,但代码冗余 import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 start_time = time.time() index(111,y=222) stop_time = time.time() print(stop_time-start_time) # 当index需要调用n次,新添的功能代码也要编写n次,代码冗余
# 解决方案二 # 解决了方案一的冗余问题,但是函数的调用方式改变了 import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 def wrapper(): start_time = time.time() index(111,y=222) stop_time = time.time() print(stop_time-start_time) wrapper()
# 方案二优化一 # 将index的参数写活 import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 def wrapper(*args,**kwargs): # args=(111,) kwargs={'y':222,} start_time = time.time() index(*args,**kwargs) # index(111,y=222) stop_time = time.time() print(stop_time-start_time) wrapper(111,y=222)
# 方案二优化二 # 在优化一的基础上把被装饰对象写活,原来只能装饰index import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 def home(name): time.sleep(1) print('my name is %s' % name) return 300 def outter(func): def wrapper(*args,**kwargs): start_time = time.time() func(*args,**kwargs): stop_time = time.time() print(stop_time-start_time) return wrapper index = outter(index) # index=wrapper的内存地址 home = outter(home) # home=wrapper的内存地址 index(111,y=222) home('yuanxiaojiang')
# 方案二的优化三 # 将wrapper做的跟被装饰对象一摸一样,以假乱真 import time def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 def home(name): time.sleep(2) print('index %s' % name) return 300 def outter(func): # func = index的内存地址 def wrapper(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) # index的内存地址 stop_time = time.time() print(stop_time-start_time) return res return wrapper index = outter(index) # index=wrapper的内存地址 home = outter(home) # home=wrapper的内存地址 res = home('yuanxiaojiang') print(res)
# 糖心法(在被装饰对象正上方单独写一行@装饰器名字) import time def timmer(func): def wrapper(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) stop_time = time.time() print(stop_time-start_time) return res return wrapper @timmer # index=timmer(index) def index(x,y): time.sleep(2) print('index %s %s' % (x,y)) return 200 @timmer # home=timmer(home) def home(name): time.sleep(2) print('index %s' % name) return 300
装饰器的叠加
@deco3 @deco2 @deco1 def index(): pass # index = deco3(deco2(deco1(index)))
wraps装饰器
from functools import wraps def outter(func): @wraps(func) def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res # 手动将原函数的属性赋值给wrapper函数 # 1、函数wrapper.__name__ = 原函数.__name__ # 2、函数wrapper.__doc__ = 原函数.__doc__ # wrapper.__name__ = func.__name__ # wrapper.__doc__ = func.__doc__ return wrapper @outter # index=outter(index) def index(x,y): """这是个主页功能""" print(x,y) print(index.__name__) print(index.__doc__) # help(index)
有参装饰器
# 添加一个为被装饰对象添加认证功能的装饰器,实现的基本形式如下 def deco(func): def wrapper(*args,**kwargs): # 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res return wrapper
from functools import wraps def auth(driver): def deco(func): @wraps(func) def wrapper(*args,**kwargs): if driver == 'file': # 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res print('基于文件的认证') res = func(*args,**kwargs) return res elif driver == 'mysql': # 编写基于mysql的认证,认证通过则执行res=func(*args,**kwargs),并返回res print('基于mysql的认证') res = func(*args,**kwargs) return res return wrapper return deco # 方式1 deco = auth(driver='file') # deco=deco函数的内存地址 @deco # index=deco(index),index=wrapper函数的内存地址 def index(x,y): print('index->>%s:%s' % (x,y)) return 200 deco = auth(driver='mysql') # deco=deco函数的内存地址 @deco # home=deco(home),home=wrapper函数的内存地址 def home(name): print('index->>%s' % name) return 300 # 方式2 @auth(driver='file') # @deco # index = deco(index) def index(x,y): print('index->>%s:%s' % (x,y)) return 200 @auth(driver='mysql') # @deco # home = deco(home) def home(name): print('index->>%s' % name) return 300
浙公网安备 33010602011771号