Python编程技巧(三)—— 装饰器

Decorators is to modify the behavior of the function through a wrapper so we don’t have to actually modify the function.
所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

@my_decorator
def greet():
    print('hello world')
greet()
# 输出
wrapper of decorator
hello world

上述代码中,把greet函数前加上my_decorator装饰器,就是把greet函数当作参数赋给func,然后wrapper函数作为装饰器的内嵌函数和闭包返回函数,被执行,wrapper中再执行greet函数,从而在不改变greet函数的基础上,增加一些功能,这些功能在wrapper函数中实现。
如果需要传递参数,可以在wrapper函数中增加,如:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper

*args和**kwargs,表示接受任意数量和类型的参数。

注意:
greet() 函数被装饰以后,它的元信息变了,它不再是以前的那个 greet() 函数,而是被 wrapper() 函数取代了。为了解决这个问题,通常使用内置的装饰器@functools.wrap,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper
    
@my_decorator
def greet(message):
    print(message)

greet.__name__
# 输出
'greet'

类装饰器

class Count:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print('num of calls is: {}'.format(self.num_calls))
        return self.func(*args, **kwargs)

@Count
def example():
    print("hello world")

example()

# 输出
num of calls is: 1
hello world

example()

# 输出
num of calls is: 2
hello world
...

类装饰器主要依赖于函数__call__(),每当你调用一个类的示例时,函数__call__()就会被执行一次。
上面代码中,定义了类 Count,初始化时传入原函数 func(),而__call__()函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example() 时,num_calls 的值是 1,而在第二次调用时,它的值变成了 2。

上一篇:SpringBoot整合MybatisPlus


下一篇:树莓派4配置RealSense with Python Wrapper