无参装饰器的实现
如果想为下述函数添加统计其时间的功能
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
index(111,333)
需求: 在不修改index函数的原代码以及调用方式的前提下为其增加统计运行时间的功能
遵循不修改被装饰对象源代码的原则,我们想到的解决方法可能是这样
解决方案一:失败
问题:没有修改被装饰对象的调用方式,但是修改了其原代码
import time
def index(x,y):
start=time.time()
time.sleep(3)
print('index %s %s'%(x,y))
stop=time.time()
print(stop-start)
index(111,333)
解决方案二:
问题:没有修改被装饰对象的调用方式,也没有修改了其原代码,并且加上了新功能,但是代码冗
余
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
start=time.time()
index(111,333)
stop=time.time()
print(stop-start)
解决方案三:失败
问题:解决了方案二的代码冗余问腿但带来了一个新问题,即函数的调用方式改变了
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
def wrapper():
start=time.time()
index(111,333)
stop=time.time()
print(stop-start)
wrapper()
解决方案三的优化一:将index的参数写活了
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
def wrapper(*args,**kwargs):
start=time.time()
index(*args,**kwargs)
stop=time.time()
print(stop-start)
wrapper()
解决方案三的优化二:
是在优化一的基础上把被装饰对象写活了,原来只能装饰index
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
def outter(func):
# func=index的内存地址
def wrapper(*args,**kwargs):
start=time.time()
func(*args,**kwargs)
stop=time.time()
print(stop-start)
return wrapper
index=outter(index) # f=outter(index的内存地址) #偷梁换柱
# f=当初那个wrapper函数的内存地址
index()
解决方案三的优化三:将wrapper做的跟被装饰对象一模一样,以假乱真
import time
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
def home(name):
time.sleep(2)
print('welcome %s to home page'%name)
return 123
def outter(func):
# func=index的内存地址
def wrapper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(stop-start)
return res
return wrapper
# 偷梁换柱:home这个名字指向的wrapper函数的内存地址
home=outter(home)
res=home('egon') # res=wrapper('egon')
print('返回值',res)
语法糖
使用方法:在被装饰对象正上方的单独一行写@装饰器名字
def outter(func):
# func=index的内存地址
def wrapper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(stop-start)
return res
return wrapper
@outter # index=outter(index)
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
index(x=1,y=2)
如果我们有多个装饰器,可以叠加多个
@deco3
@deco2
@deco1
def index():
pass
# 叠加多个装饰器无特殊之处,上述代码语义如下:
index=deco3(deco2(deco1(index)))
总结无参装饰器模板
def outter(func):
def wrapper(*args,**kwargs):
#1、调用函数
#2、为其添加新功能
res=func(*args,**kwargs)
return res
return wrapper
wraps装饰器
wraps:将wrapper获得跟原函数一模一样的属性
from function import wraps
def outter(func):
@wraps(func)
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
@outter
def index(x,y):
time.sleep(3)
print('index %s %s'%(x,y))
有参装饰器
def auth(db_type):
def deco(func):
def outter(*args,**kwargs):
name=input('your name>>>: ')
pwd=input('your password>>>: ')
if db_type=='fire':
print('基于文件的验证')
if name=='egon' and pwd == '123':
res=func(*args,**kwargs)
return res
else:
print('user or password error')
elif db_type=='mysql':
print('基于mysql的验证')
elif db_type=='ldap':
print('基于ldap的验证')
else:
print('不支持该db_type')
return deco
return auth
@auth(db_type='fire') # 账号密码来源是文件 运行顺序:@deco # index=deco(index) # index=wrapper
def index(x,y):
print('index->>>%s:%s'%(x,y))
@auth(db_type='mysql') # 账号密码来源是数据库 运行顺序:@deco # home=deco(home) # home=wrapper
def home(name):
print('home->>>%s'%name)
@auth(db_type='ldap') # 账号密码来源是ldap 运行顺序:@deco # transfer=deco(transfer) # transfer=wrapper
def transfer():
print('transfer')
index(1,2) # wrapper(1,2)
home('star')
transfer()
有参装饰器模板
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass