Python 装饰器常用的创建方式及源码示例解析

装饰器简介

装饰器(decorator)是一种高级Python语法。可以对一个函数、方法或者类进行加工。在Python中,我们有多种方法对函数和类进行加工,相对于其它方式,装饰器语法简单,代码可读性高。因此,装饰器在Python项目中有广泛的应用。修饰器经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理, Web权限校验, Cache等。

装饰器的优点是能够抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。即,可以将函数“修饰”为完全不同的行为,可以有效的将业务逻辑正交分解。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。例如记录日志,需要对某些函数进行记录。笨的办法,每个函数加入代码,如果代码变了,就悲催了。装饰器的办法,定义一个专门日志记录的装饰器,对需要的函数进行装饰。

基础通用装饰器

源码示例

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 --")
        print("-- inner_2 end --")
    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 方法来满足被装饰函数的执行触发

到此这篇关于Python 装饰器常用的创建方式及解析的文章就介绍到这了,更多相关python装饰器创建方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(Python 装饰器常用的创建方式及源码示例解析)