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。