一 装饰器介绍
为何要用装饰器软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。
软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃,而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器。
什么是装饰器
’装饰’代指为被装饰对象添加新的功能,’器’代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景,装饰器是解决这类问题的绝佳设计,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
提示:可调用对象有函数,方法或者类,此处我们单以本章主题函数为例,来介绍函数装饰器,并且被装饰的对象也是函数。
二 装饰器的实现
函数装饰器分为:无参装饰器和有参装饰两种,二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。
无参装饰器的实现
如果想为下述函数添加统计其执行时间的功能
import time
def index():
time.sleep(3)
print("开心")
def outer(func):
def get_time():
star_time = time.time()
func()
end_time = time.time()
print(f"程序执行了{end_time - star_time}秒")
return get_time
index = outer(index)
index()
有参装饰器的实现
import time
def index(name):
time.sleep(3)
print("开心",name)
def outer(func):
def get_time(*args,**kwargs):
star_time = time.time()
func(*args,**kwargs)
end_time = time.time()
print(f"程序执行了{end_time - star_time}秒")
return get_time
index = outer(index)
index("lgj")
有返回值装饰器的实现
import time
def index():
time.sleep(3)
print("开心")
return "真开心呀"
def outer(func):
def get_time():
star_time = time.time()
set = func()
end_time = time.time()
# print(f"程序执行了{end_time - star_time}秒")
tj_time=end_time-star_time
return set,tj_time
return get_time
index = outer(index)
print(index())
装饰器练习题(认证登录功能)
def index():
print("看到本信息,就是登录成功了")
def outer(func):
def login(*args,**kwargs):
user_name=input("请输入你的用户名:").strip()
user_password=input("请输入你的密码:").strip()
if user_name=="lgj" and user_password=="123123":
func(*args,**kwargs)
else:
print("登陆失败")
return login
index = outer(index)
index()
装饰器的固定模板
def outer(func):
def inner(*args, **kwargs):
print('函数被调用之前需要添加的功能')
res=func(*args, **kwargs) # 真正的函数执行
print('函数被调用之后需要添加的功能')
return res
return inner
def outer(func):
def inner(*args, **kwargs):
print('函数被调用之前需要添加的功能')
res = func(*args, **kwargs) # 真正的函数执行
print('函数被调用之后需要添加的功能')
return res
return inner
# @outer # index = outer(index)
# def index():
# print('from index')
# return 'index'
#
#
# @outer # home=outer(home)
# def home():
# print('from home')
#
# # index = outer(index)
#
# index()
#
# home() # inner()
@outer # func=outer(func)
def func():
print('from func')
func()
"""
1. 语法糖的书写规范:
@装饰器名字
必须把上面的写在被装饰对象的头上(紧贴着被装饰对象写)
2. 语法糖的原理:
它会把下面的被装饰对象的名字当成参数传递给装饰器
"""