装饰器的概念
就是给被装饰对象添加新功能的工具,作用是在不改变原有被装饰对象代码和调用方式的情况下,为装饰对象添加新的功能。
装饰器分为有参装饰器和无参装饰器,都是基于函数嵌套、闭包、函数对象实现的
装饰器的简易版本
#先写一个被装饰的函数
import time
def index():
print('index')
time.sleep(3)
现在我们想为这个函数增加一个统计其运行时间的功能
start_time=time.time()
index()
end_time=time.time()
print('当前函数运行时间为%s' %(end_time-start_time))
现在虽然原函数调用方式和源代码都没有被改变,但是如果多处使用的话,就会造成代码重复和冗余,这个时候就需要利用函数把这个功能整合起来
def inner():
start_time = time.time()
index()
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
inner()
但是index这个地方的函数名就写死了,如果别的函数也需要添加这个功能就需要修改,所以我们把这个地方的index换成参数形式
def inner(func):
start_time = time.time()
func()
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
inner(index)
这里index的调用方式就发生了改变,所以这不是装饰器了。我们需要利用闭包函数的第二种传值方式。
def outer(func):
# func=index
def inner():
start_time = time.time()
func()
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
return inner#记得把inner返回给outer
# res=outer(index)
# res()
index=outer(index)#注意此时的index已经不是原来函数的index了,而是inner的内存地址
index()#inner()
这时的原函数的代码没有被修改,调用方式也没有被改变。这就是一个简易版的无参装饰器。
装饰器进阶版本
解决参数问题
但是如果涉及到被装饰函数的参数,就会报错
import time
def index(a,b):
print('index')
time.sleep(3)
def outer(func):
# func=index
def inner():#由于没有接收的参数所以会报错
start_time = time.time()
func()
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
return inner#记得把inner返回给outer
# res=outer(index)
# res()
index=outer(index)#注意此时的index已经不是原来函数的index了,而是inner的内存地址
index(1,2)#inner()
这个时候就需要用到可变长参数
def outer(func):
# func=index
def inner(*args,**kwargs):#参数接收变成元组和字典形式
start_time = time.time()
func(*args,**kwargs)#元组和字典形式的参数打散成位置参数和关键参数
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
return inner#记得把inner返回给outer
# res=outer(index)
# res()
index=outer(index)#注意此时的index已经不是原来函数的index了,而是inner的内存地址
index(1,2)#inner()
解决返回值问题
但是inner依旧伪装的不够像,没有和被装饰函数相同的返回值,这个时候我们就给他赋值
def outer(func):
# func=index
def inner(*args,**kwargs):#参数接收变成元组和字典形式
start_time = time.time()
res=func(*args,**kwargs)#相当于index的return返回值给res
end_time = time.time()
print('当前函数运行时间为%s' % (end_time - start_time))
return res#这里inner返回的值就和index也就是被装饰对象是同一个返回值了
return inner#记得把inner返回给outer
# res=outer(index)
# res()
index=outer(index)#注意此时的index已经不是原来函数的index了,而是inner的内存地址
index(1,2)#inner()
装饰器练习题
写一个登录功能的装饰器,要求在验证成功后,后续函数登录就不需要验证了
def index():
print('from index')
def home():
print('from home')
def abcd():
print('from index1')
is_login={'is_login':False}
def outer(func):
def inner(*args,**kwargs):
if is_login.get('is_login'):
res=func()
return res
username = input('username:>>>').strip()
password = input('password:>>>').strip()
if username == 'kk' and password == '123':
# 执行函数
print('登录成功')
res=func(*args,**kwargs)
is_login['is_login'] = True
return res
else:
print('用户名或者密码错误')
return inner
index=outer(index)
index()
home=outer(home)
home()
abcd=outer(abcd)
abcd()
装饰器的固定模板
def index(func):
print('index')
def outer():
def inner(*args,**kwargs):
print('被装饰对象前的代码')
res=func(*args,**kwargs)
print('被装饰对象后的代码')
return res
return inner
index=outer(index)
index()