【python】decorator 装饰器

151 阅读3分钟

python中的装饰器其实是闭包这种思路的一种应用

闭包

在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了。

案例:

def outer(x):
    def inner(y):
        return x+y;
    return inner

print(outer(1)(2))    # 3

说明:调用outer函数,传入参数1,返回一个函数inner,然后调用inner函数,传入参数2,返回结果。

简单装饰器

装饰器本质上就是闭包的一种应用

装饰器其实就是传进去一个函数,然后在调用该函数之前,做一些其它事情,然后再返回新的函数。其实本质上就是在不影响原来函数功能的基础上为其添加新的功能。

案例:

def debug(func):
    def wrapper():
        print(f'[DEBUG]: Test Bug {func.__name__}')  # 新的功能
        return func()  # 调用原函数,并返回原函数的返回值
    return wrapper  # 返回新的函数

@debug
def hello():
    print('Hello world!')
    return 1

print(hello())

"""
[DEBUG]: Test Bug hello
Hello world!
1
"""

说明:使用debug函数作为装饰器,将函数hello传入到debug中,返回一个经过处理的新函数wrapper,调用函数wrapper(),执行添加的代码后,调用原函数并返回原函数的返回值。

带参数的装饰器

其实就是再向外添加一层函数,最外层函数的参数用于装饰器传参

案例:

def debug(pattern):
    def out_wrapper(func):
        def wrapper():
            print(f'[{pattern}]: Test Debug')
            return func()
        return wrapper
    return out_wrapper

@debug(pattern='DEBUG')
def hello():
    print('Hello world!')
    return 1

print(hello())
"""
[DEBUG]: Test Debug
Hello world!
1
"""

说明:使用debug函数作为装饰器,先传入装饰器参数到最外层函数,返回一个新的函数out_wrapper,out_wrapper接收原函数hello作为参数,返回一个新的函数wrapper,调用函数wrapper,先执行新添加的代码,然后执行原函数并返回原函数的返回值。

类装饰器

装饰器也不一定只能用函数来写,也可以使用类装饰器,用法与函数装饰器并没有太大区别,实质是使用了类方法中的魔法方法__call__来实现类的直接调用。

不带参数的类装饰器

class debug(object):
    def __init__(self,func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('[DEBUG]: Test Debug')
        return self.func(*args, **kwargs)

@debug
def hello():
    print('Hello world!')
    return 1

print(hello())
"""
[DEBUG]: Test Debug
Hello world!
1
"""

说明:

该类的初始化方法接收hello函数作为参数进行初始化,然后当该函数被调用时,调用该类的__call__方法,原函数的参数被__call__方法的参数接收,执行完新添加的代码后,执行原函数并返回原函数的返回值。

__call__ 是 Python 中的魔法方法,用于将一个类的实例像函数一样进行调用。当一个对象被调用时,Python 会自动调用该对象的__call__ 方法,所以当加上装饰器后,其实可以把原函数看成是该类的实例化对象。

带参数的类装饰器

class debug(object):
    def __init__(self,pattern):
        self.pattern = pattern

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(f'[{self.pattern}]: Test Debug')
            return func(*args, **kwargs)
        return wrapper

@debug('DEBUG')
def hello():
    print('Hello world!')
    return 1

print(hello())
"""
[DEBUG]: Test Debug
Hello world!
1
"""

说明:装饰器参数被该类的初始化方法接收,并初始化作为属性,当被修饰函数hello被调用时,调用__call__方法,接收原函数作为参数,返回一个新的函数wrapper,wrapper接收原函数的参数,执行完新添加的代码后,执行原函数并返回原函数的返回值。