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。