Python 装饰器常用的创建方式及解析
基础通用装饰器
源码示例
def wrapper_out(func): print('-- wrapper_out start --') def inner(*args, **kwargs): print("-- inner start --") ret = func(*args, **kwargs) print("-- inner end --") return ret print('-- wrapper_out end --') return inner @wrapper_out def test(): print("--test--") return 1 * 2 if __name__ == '__main__': print(">>>>>>>>>>>>>>") print(test())
执行结果
-- wrapper_out start -- -- wrapper_out end -- >>>>>>>>>>>>>> -- inner start -- --test-- -- inner end -- 2
带参数装饰器
源码示例
def wrapper_out(mode=None): print('-- wrapper_out start --') def inner_1(func): print("-- inner_1 start --") def inner_2(*args, **kwargs): print("-- inner_2 start --") print(f"mode: {mode}") ret = func(*args, **kwargs) print("-- inner_2 end --") return ret print("-- inner_2 end --") return inner_2 print('-- wrapper_out end --') return inner_1 @wrapper_out(mode=2) def test(): print("--test--") return 1 * 2 if __name__ == '__main__': print(">>>>>>>>>>>>>>") print(test())
源码结果
-- wrapper_out start --
-- wrapper_out end --
-- inner_1 start --
-- inner_2 end --
>>>>>>>>>>>>>>
-- inner_2 start --
mode: 2
--test--
-- inner_2 end --
2
源码解析
带参数的装饰器函数, 需要多嵌套一层, 外层装饰器的参数
预加载的时候已经是根据函数的编写顺序进行加载
执行顺序在对应的最内存函数中调用最外层的装饰器函数参数
被装饰函数是最为 inner_1 的参数进行传入, 被装饰函数的参数是作为 inner_2 的参数传入
被装饰函数的执行位置是在 inner_2 中, 使用inner_1 的参数变量和 inner_2 的参数变量共同协助下进行执行
同时还要使用装饰器函数 wrapper_out 的参数变量进行额外的操作
多装饰器执行顺序
源码示例
def wrapper_out1(func): print('-- wrapper_out_1 start --') def inner1(*args, **kwargs): print("-- inner_1 start --") ret = func(*args, **kwargs) print("-- inner_1 end --") return ret print('-- wrapper_out1 end --') return inner1 def wrapper_out2(func): print('-- wrapper_out_2 start --') def inner2(*args, **kwargs): print("-- inner_2 start --") ret = func(*args, **kwargs) print("-- inner_2 end --") return ret print('-- wrapper_out_2 end --') return inner2 @wrapper_out2 @wrapper_out1 def test(): print("--test--") return 1 * 2 if __name__ == '__main__': print(">>>>>>>>>>>>>>") print(test())
执行结果
-- wrapper_out_1 start -- -- wrapper_out1 end -- -- wrapper_out_2 start -- -- wrapper_out_2 end -- >>>>>>>>>>>>>> -- inner_2 start -- -- inner_1 start -- --test-- -- inner_1 end -- -- inner_2 end --
2
解析
装饰器的预加载顺序是从上往下, 先将装饰器函数写入内存
装饰器的执行顺序是以最靠近函数体的装饰器开始执行(从内到外)
多个装饰器装饰函数时,规律是从下到上包裹(装饰)函数,然后从上到下执行。
类装饰器
源码示例
class WrapperOut(object): def __init__(self, func): print('start init ~~~~~`') print('func name is %s ' % func.__name__) self.__func = func print('end init ~~~~~`') def __call__(self, *args, **kwargs): print('start test') self.__func() print('end test') @WrapperOut def test(): print('this is test func') if __name__ == '__main__': print(">>>>>>>>>>>") test()
执行结果
start init ~~~~~` func name is test end init ~~~~~` >>>>>>>>>>> start test this is test func end test
解析
类装饰器是利用了类初始化 init 析构方法来处理 被装饰函数的传入
以及使用 call 方法来满足被装饰函数的执行触发
本文来自博客园,作者:羊驼之歌,转载请注明原文链接:https://www.cnblogs.com/shijieli/p/16185776.html