装饰器(Decorators)是 Python 的一个重要部分。所谓的装饰器,就是修改其他函数的功能的函数,使用装饰器可以在不改变原函数的基础上扩充原函数功能。
函数也是对象
在 Python 中,函数是头等公民(First-class Citizen),其本身是一个对象,这意味着:
- 可以把函数赋予变量;
- 可以在函数内部定义函数(函数嵌套);
- 函数可以作为其他函数的参数传递;
- 函数的返回值也可以是函数对象(闭包)。
示例:函数的嵌套与闭包
| def outer_func(): name = "I'm closure"
def inner_func(msg): print(f'{msg}{name}')
return inner_func
closure = outer_func() closure('Hello, ')
|
函数装饰器
示例一:函数装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def decorator(func): def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs)
return wrapper
@decorator def greet(msg): print(f'{msg}, world')
greet('hello') greet('goodbye')
|
示例二:带参数的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def repeat(num): def decorator(func): def wrapper(*args, **kwargs): for i in range(num): print('wrapper of decorator') func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) def greet(msg): print(msg)
greet('hello world')
|
示例三:装饰器的嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| """ Python也支持多个装饰器,比如写成下面这样的形式,它的执行顺序从上到下: @decorator1 @decorator2 @decorator3def func(): ... 上面的语句等同于下面这行代码: func = decorator1(decorator2(decorator3(func))) """
def decorator1(func): def wrapper(*args, **kwargs): print('call decorator1') func(*args, **kwargs)
return wrapper
def decorator2(func): def wrapper(*args, **kwargs): print('call decorator2') func(*args, **kwargs)
return wrapper
@decorator1 @decorator2 def greet(message): print(message)
greet('hello world')
|
示例四:保留原函数的元信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| def decorator(func): def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs)
return wrapper
@decorator def greet(msg): print(msg)
print(greet.__name__) help(greet)
---------
import functools
def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs)
return wrapper
@decorator def greet(msg): print(msg)
print(greet.__name__) help(greet)
|
类装饰器
除了函数可以作为装饰器,类也可以作为装饰器。类装饰器主要依赖于 __call__()
函数,每当调用一次类的实例时,__call__()
函数就会被执行一次。
示例:构建类装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Count(object): def __init__(self, func): self.func = func self.num_calls = 0
def __call__(self, *args, **kwargs): self.num_calls += 1 print(f'num of calls is: {self.num_calls}') return self.func(*args, **kwargs)
@Count def greet(): print('hello world')
for _ in range(3): greet()
|