一、有参装饰器
无参装饰器的用法,模板如下:
def outter(func):#参数写死,为了给语法糖传值 def warpper(*args,**kwargs):#参数写死,为了给func传值 res = func(*args,**kwargs) return res return warpper @outter def index(): print("这是主页") return 1 res = index() print(res) >>>这是主页 >>>1 >>>从这段模板代码我们可以看出,装饰器的两个函数我们都无法为它增加新的参数传值
所以,当我们的装饰器需要跟多参数的时候,就只能通过闭包函数为他传值
2 如何使用有参装饰器
下面通过一个需求来表现有参装饰器的用途:
例:编写装饰器对多个函数添加认证功能,如果登录成功过,其他函数就不需要再次登录
分析需求:我们要编写认证功能的话只要添加个简单的有判断的装饰器即可,但是要判断之前是否成功过,我们就需要用到全局变量,如果登录成功把全局变量修改即可。所以我们在装饰器内部就要再判断一下,这个全局变量的值是什么,这里就会出现矛盾
我们要先判断全局变量,如果没有登录过,就修改他的值,这里违背了变量的先定义后引用的原则
所以基于这个矛盾,我们需要对装饰器传值,而在上面模板中我们已经知道,装饰器的函数我们都无法为他传值,因为各有用途都写死了。所以我们只能用第二种传值方式:闭包
is_login = True
def auth(login):
def outter(func):
def warpper(*args,**kwargs):
if login:
name = input("你的名字:")
pwd = input("你的密码:")
if name == "hz" and pwd == "123":
print("登录成功")
func(*args,**kwargs)
global is_login
is_login=False
else:
print("输入错误")
else:
func(*args,**kwargs)
return warpper
return outter
#语法糖的定义:被装饰函数 = @后面的东西(被装饰的函数)
#index = auth(is_login)(index)
#auth(is_login) == outter
#outter(index) ==warpper
@auth(is_login)
def index():
print("你好")
index()
@auth(is_login)
def home():
print("欢迎回家")
home()
3 有参装饰器模板
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
4 修正装饰器
我们的装饰器最终目的就是要把(原函数+装饰器)修改成和没有修改的函数一样(属性上)
但是,我们之前的学习装饰器还没有完成最终目的
@timer
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page',name)
print(help(home))
'''
打印结果:
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
None
每个函数在定义出来后就有非常多的属性,名字,注释等等,我们如果一一修改就非常麻烦,这里可以用functools模块下提供的一个装饰器wraps专门用来帮我们实现这个:
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper