Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数
练习
# 装饰器 def decorator_1(func): print(f"装饰1:{func}") def inner(*args, **kwargs): print(f"inner1:{func}") return func(*args, **kwargs) return inner # 带有参数的装饰器 def decorator_2(arg): def decorator_2_(func): print(f"装饰2:{func}") def inner(*args, **kwargs): print(f"inner2:{func}") print(f"decorator_2 参数:{arg}") return func(*args, **kwargs) return inner return decorator_2_ # 类装饰器 class Decorator_cls(object): def __init__(self, func): self.func = func print(f"装饰cls:{self.func}") def __call__(self, *args, **kwargs): print(f"cls__call__:{self.func}") return self.func(*args, **kwargs) # 多个装饰器装饰一个函数 @decorator_1 # sum_func = decorator_1(sum_func) @decorator_2("abc") @Decorator_cls def sum_func(a, b=0): sum_ = a + b return sum_ result = sum_func(1, b=2) print(f"结果:{result}")
运行结果:
装饰cls: 装饰2:<__main__.decorator_cls object at 0x00000000023FA700> 装饰1:.decorator_2_..inner at 0x00000000026A2160> inner1:.decorator_2_..inner at 0x00000000026A2160> inner2:<__main__.decorator_cls object at 0x00000000023FA700> decorator_2 参数:abc cls__call__: 结果:3
Python多个装饰器的执行顺序
当Python函数被多个装饰器装饰时,装饰顺序和执行顺序是怎样的,用一个简单的例子来说明
def decorator_a(func): print('Get in decorator_a') def inner_a(*args, **kwargs): print('Get in inner_a') return func(*args, **kwargs) return inner_a def decorator_b(func): print('Get in decorator_b') def inner_b(*args, **kwargs): print('Get in inner_b') return func(*args, **kwargs) return inner_b @decorator_b @decorator_a def f(x): print('Get in f') return x * 2 if __name__ == '__main__': a = f(2) print("a =",a)
执行文件得到的结果是:
Get in decorator_a Get in decorator_b Get in inner_b Get in inner_a Get in f a = 4
我们来分析一下,为什么会是这样的顺序:
首先注释掉代码的执行部分,即a = f(2),执行文件,只打印两行:
Get in decorator_a Get in decorator_b
这说明装饰器函数在被装饰函数定义好后就立即执行。
而且执行顺序是由下到上开始装饰。调用decorator_a时,f被装饰成inner_a,调用decorator_b时,f被装饰成inner_b。
通过在最后执行:print(f),可验证。
def decorator_a(func): ... return inner_a def decorator_b(func): ... return inner_b @decorator_b @decorator_a def f(x): print('Get in f') return x * 2 if __name__ == '__main__': print(f)
执行结果为:
Get in decorator_a Get in decorator_b .inner_b at 0x0000019C6FC62820>
所以当调用函数执行时,a=f(2),f已经变成了inner_b,而inner_b中return的func,实则为inner_a,inner_a中return的func才是最终的f。
所以最后的调用顺序为:
inner_b —>inner_a—>f
执行部分打印的结果就为:
Get in inner_b Get in inner_a Get in f a = 4
总结:
多个装饰器装饰函数时,规律是从下到上包裹(装饰)函数,然后从上到下执行。
练习 类中使用装饰器
def decorator(arg): print(f"decorator 参数:{arg}") def inner1(func): print(f"decorator inner1 参数:{func}") def inner2(*args, **kwargs): print(f"decorator inner2 参数:args {args}, kwargs {kwargs}") return func(*args, **kwargs) return inner2 return inner1 class Test(object): def __init__(self): self.func_a(2, 3) @decorator(1) def func_a(self, *args, **kwargs): print(f"func_a 参数: args {args}, kwargs {kwargs}") def func_b(self): self.func_a(2, 3) if __name__ == '__main__': obj = Test() # obj.func_a(2, 3) # obj.func_b()
练习
# 类装饰器带参数 class Outer(object): def __init__(self, arg): self.arg = arg print(f"Outer arg:{self.arg}") class DecoratorCls(object): def __init__(self, func): self.func = func print(f"装饰cls:{self.func}") def __call__(self, *args, **kwargs): print(f"cls__call__:{self.func}") return self.func(*args, **kwargs) def __call__(self, func): print(f"outer__call__:{self.DecoratorCls}") return self.DecoratorCls(func) @Outer('is outer arg') # sum_func = Outer('is outer arg')(sum_func) def sum_func(a, b=0): sum_ = a + b return sum_ result = sum_func(1, b=2) print(f"结果:{result}")
运行结果:
Outer arg:is outer arg outer__call__:<class '__main__.Outer.DecoratorCls'> 装饰cls: cls__call__: 结果:3