装饰器
普通装饰器
import time
def outer_func(func):
def inner_func():
start_time = time.time()
func()
end_time = time.time()
print(f'函数test_func运行时长: {end_time - start_time}')
return inner_func
@outer_func
def test_func():
time.sleep(1)
def main():
# 重点:
# 装饰器本质上是把被装饰的函数当作参数传入并反回一个同名函数
# 解释:
# 调用被装饰过的函数test_func时实际上调用outer_func(test_func)
# 所以 test_func 就是 outer_func(test_func)
# 因此 test_func() 就是 outer_func(test_func)()
# outer_func(test_func)() 中的 outer_func(test_func) 反回 inner_func
# 所以就是 inner_func()
# inner_func() 内部可以调用外部函数的参数,也就是func,而func才是真真的test_func
# 所以 inner_func() 内部调用了 test_func()
test_func()
if __name__ == '__main__':
main()
多层装饰器
def outer_func_1(func):
def inner_func():
print('装饰器outer_func_1运行开始')
func()
print('装饰器outer_func_1运行结束')
return inner_func
def outer_func_2(func):
def inner_func():
print('装饰器outer_func_2运行开始')
func()
print('装饰器outer_func_2运行结束')
return inner_func
@outer_func_2
@outer_func_1
def test_func():
print("我才是test_func函数")
def main():
test_func()
if __name__ == '__main__':
main()
输出:
装饰器outer_func_2运行开始
装饰器outer_func_1运行开始
我才是test_func函数
装饰器outer_func_1运行结束
装饰器outer_func_2运行结束
解释:
-
多层装饰器由外向内调用,由内向外反回
-
根据装饰器的本质,实际执行的是 test_func = outer_func_2(outer_func_1(test_func)),分解开就是:
1、outer_func_1 = outer_func_2(outer_func_1)
2、test_func = outer_func_1(test_func)
- 首先是过程1,调用的outer_func_1其实是outer_func_2反回的同名函数,所以实际执行的是outer_func_2函数,因此第一个输出是“装饰器outer_func_2运行开始”
其次是过程2,调用的test_func其实是outer_func_1反回的同名函数,所以实际执行的是outer_func_1函数,因此第二个输出是“装饰器outer_func_1运行开始”
然后开始执行真正的函数test_func,因此第三个输出是“我才是test_func函数”
最后是依次反回上层函数outer_func_1、outer_func_2,因此第三个输出“装饰器outer_func_1运行结束”,第四个输出“装饰器outer_func_2运行结束”
被装饰的函数有返回值
def outer_func(func):
def inner_func():
# 当被装饰的函数有返回值
# 此处不能仅仅是调用 func(), 否则不会输出 Hello World!
# 而是需要返回调用
return func()
return inner_func
@outer_func
def test_func():
return 'Hello World!'
def main():
print(test_func())
if __name__ == '__main__':
main()
被装饰的函数有参数
代码1
def outer_func(func):
def inner_func(name, age):
func(name, age)
return inner_func
@outer_func
def introduce(name, age):
print(f'我是{name}今年{age}岁')
def main():
introduce('谁', '几')
if __name__ == '__main__':
main()
代码2
def outer_func(func):
def inner_func(*args, **kwargs):
func(*args, **kwargs)
return inner_func
@outer_func
def print_parmeter(a, b, *args, **kwargs):
print(a, b)
print(f'args:{args}')
print(f'kwargs:{kwargs}')
def main():
print_parmeter(1, 2, 3, 4, 5, key1='value1', key2='value2')
if __name__ == '__main__':
main()
输出:
1 2
args:(3, 4, 5)
kwargs:{'key1': 'value1', 'key2': 'value2'}
装饰器工厂
即函数内部定义了装饰器,最后反回这个装饰器,即该函数创建了一个装饰器,所以叫装饰器工厂
def wraps_factory():
def outer_func(func):
def inner_func():
func()
return inner_func
return outer_func
# 注意这里,后来带了括号
# 使用装饰器无需带括号,使用装饰器功能需带括号
@wraps_factory()
def test_func():
print('Hello World')
def main():
test_func()
if __name__ == '__main__':
main()
上面的示例意义不大,因为用装饰器就能完成,不需要装饰器工厂
装饰器工厂的真正意义在于给装饰器携带参数,具体看下面的例子
装饰器与被装饰器都有参数
装饰器本身可以携带参数,那必定是装饰器工厂,因为只有装饰器工厂可以带参数
def wraps_factory(factory):
def outer_func(func):
def inner_func(parm=None):
if parm:
func(parm)
else:
# 装饰器的参数可以被内部使用
func(factory)
return inner_func
return outer_func
@wraps_factory('abc')
def test_func(parm=None):
print(f'factory name is {parm}')
def main():
test_func() # 等同于 wraps_factory('abc')(test_func)(parm=None)
test_func('xyz') # 等同于 wraps_factory('abc')(test_func)(parm='xyz')
if __name__ == '__main__':
main()
wraps_factory('abc')(test_func)(parm=None)
wraps_factory('abc')(test_func)(parm='xyz')
输出:
factory name is abc
factory name is xyz
装饰器类
装饰器类需要实现两个方法:__init__ 和 __call__
__init__接收一个参数,即被装饰的函数, 相当于outer_func(func)
__call__ 负责处理业务,相当于inner_func()
class Wraps:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwds):
print('开始装饰')
func = self.func(*args, **kwds)
print('装饰结束')
return func
@Wraps
def test_func(num1, num2):
for i in range(num1, num2):
print('Hello World')
def main():
test_func(1,3)
if __name__ == '__main__':
main()