由于软件的设计遵循开发封闭原则(对于扩展开发,对于程序修改封闭)。所以对于软件的扩展是对软件二次开发的最好途径。这时候就需要使用到装饰器这个概念了。
装饰器就是为装饰的对象添加新的功能,并且是在不修改源码的情况下,还必须使得在外行看起来没有发生任何变化(调用方法、软件实现主要功能……)。
装饰器分为无参装饰器和有参装饰器,装饰器的实现都是通过“函数嵌套+闭包+函数对象”组合生成的。
装饰器模板
def outter(func):
# 传进来的是被装饰的函数的对象
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
@outter
def index(x,y):
print(x,y)
无参装饰器的实现
import time
# 定义一个小函数
def index():
time.sleeep(1.5)
print("Welcome to index page!!!")
return 100
index() # 调用函数
如果需要在这个函数调用时候添加一个功能:就是实现输出调用函数需要使用的时间,虽然说这个功能实现很简单,并没有什么复杂的,但是如果只是使用下面的这种解法,那么就太老土了。
解法一:(老土、麻烦)
start = time.time()
index() # 调用函数
print("用时:",time.time()-start)
这样子对于只是一个两个函数的时候,就能够简单实现,但是如果很多的函数调用都需要输出时间的时候就会很麻烦了,代码量也会变得很累赘了。
解法二:(调用方式改变了,不是很合要求)
def timer(fun):
start = time.time()
fun() # 调用函数
print("用时:",time.time()-start)
timer(index) # 调用一个新的函数,实现所需要的功能
这个方法是对第一个方法的改进,减少了代码量,但是同时也带来了一个缺点,那就是改变了调用方式,这样子好像不太满足要求了。
解法三:(使用装饰器)
import time
def timer(func):
def wrapper(): # 引用外部作用域的变量func
start_time=time.time()
res=func()
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
# 定义一个小函数
@ timer # 添加装饰器对象
def index():
time.sleeep(1.5)
print("Welcome to index page!!!")
return 100
# 这时候的调用方式
index() # 调用函数,但是这时候调用的函数就不再是原先的index函数了,而是加了装饰器的index函数
使用装饰器之后,调用方式没有发生任何的改变,同时也实现了附加的功能;同时如果还有其他的函数想要实现这个种附加的功能也这需要添加一个装饰器就可以了。
有参装饰器的实现
由于语法糖 @ 的限制,outter函数只能有一个参数,并且这才是只用来接受被装饰对象的内存地址
# 定义一个验证功能的装饰器
def auth(driver): # 最高层传递参数(第三层)
def deco(func):
def wrapper(*args,**kwargs):
name = input("input user>>").strip()
pwd = input("input pwd>>").strip()
if driver == 'file':
print("基于文件验证")
# 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res
# 打开文件,传文件中读取用户信息进行匹配
if name == "xiaoming" and pwd == "123456":
print("基于文件验证成功")
else:
print("基于文件验证失败")
elif driver == 'mysql':
# 编写基于mysql认证,认证通过则执行res=func(*args,**kwargs),并返回res
print("基于数据库验证")
if name == "xiaoming" and pwd == "123456":
print("基于数据库验证成功")
else:
print("基于数据库验证失败")
else:
print("传入验证参数有误")
return wrapper
return deco
# auth(driver="file") ----- 运行之后返回一个deco函数的内存地址;(添加这一层闭包的主要功能就是为了传递参数)
# @deco 这个就是一般的装饰器语法糖(一个两层的闭包函数)
@auth(driver="file")
def index(x,y):
print("index{}{}".format(x,y))
@auth(driver="mysql")
def home(x,y):
print("index{}{}".format(x,y))
index(2,6)
home(5,9)
综合以上操作就实现了有参装饰器的传递,但是还存在一个问题,就是虽然有参装饰器是实现了,并且调用方式都没发生任何的变化,但是还有一个问题,那就是函数的属性以及一些其他的附加内容,并没有进行修改,这时候其实需要把他们全部进行修改才是一个完美的装饰器。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115127.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...