一、装饰器作用
1.装饰器可以实现,在不修改原来函数的代码时,进行功能的扩展。实现了代码的封装,同时扩展了功能,也不会重复执行。
二、多个装饰器修饰同一函数代码
# 闭包实现装饰器
def add_authorization(func):
# 扩展的控制权限验证的代码
print("*******开始执行装饰权限的功能******")
def call_func(*args, **kwargs):
print("*****验证权限*****")
return func(*args, **kwargs)
return call_func
def add_log(func):
# 增加的记录日志的代码
print("******开始装饰记录日志功能*******")
def call_func(*args, **kwargs):
print("*****日志*****")
return func(*args, **kwargs)
return call_func
@add_authorization
@add_log
def test(*args, **kwargs):
# 原来的代码
print("-------test-------")
return "test is ok..."
if __name__ == "__main__":
ret = test()
print(f"ret = {ret}")
运行结果:
******开始装饰记录日志功能*******
*******开始执行装饰权限的功能******
*****验证权限*****
*****日志*****
-------test-------
ret = test is ok...
上面的add_authorization和add_log就是装饰器。用于装饰函数test。
三、代码解析
代码从上向下执行,执行到
@add_authorization
@add_log
- 先执行下面的装饰器add_log。
@add_log # 等价于 test = add_log(test)
执行之后:
add_log.func = test
test = add_log.call_func
add_log的形参add_log.func指向test函数指向的内存空间,可以理解为函数入口地址下次调用func时就是执行该空间的代码;之后test指向add_log.call_func引用的内存空间,即调用test时,就是执行该内存里的代码。
2.在执行上面的装饰器add_authorization
@add_authorization
# 表面上等价于 test = add_authorization(test)
# 实际上由于执行了add_log,导致test=add_log.call_func
# 实际上等价于 test = add_authorization(add_log.call_func)
执行之后:
add_authorization.func = add_log.call_func
test = add_authorization.call_func
3.综上可得:
add_log.func = test # 3
add_authorization.func = add_log.call_func # 2
test = add_authorization.call_func # 1
add_log.func指向了原来test指向的内存空间。add_authorization.func指向了add_log.call_func指向的内存空间。而test 指向了 add_authorization.call_func指向的内存空间。
所以调用test时,先去执行add_authorization.call_func的代码,之后在执行add_log.call_func的代码,最后再执行原来的test执行的代码。
总之,多个装饰器修饰同一个函数时,装饰的时候从下向上开始装饰。而调用的时候从上向下开始依次调用 执行代码。