装饰器(decorator)能在不改变原函数代码的前提下,给它增加额外功能,比如计时、日志、权限校验。它是 Python 优雅设计的典范。
一、本质:函数也是对象
Python 里函数是一等对象,可以赋值给变量、作为参数传递、作为返回值。装饰器正是利用这一点。
二、手写一个计时装饰器
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.time()-start:.3f}s")
return result
return wrapper
@timer
def my_func():
time.sleep(1)
print("执行完毕")
@timer 等价于 my_func = timer(my_func)。
三、带参数的装饰器
需要三层嵌套来接收参数:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 重复执行 3 次
def greet():
print("hi")
四、用 functools.wraps 保留原信息
装饰后,函数的 __name__ 等元信息会变成 wrapper 的。用 @wraps 修复:
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
...
return wrapper
实战中装饰器常用于:日志记录、性能监控、权限校验、缓存(@lru_cache)、重试机制等。是 DRY 原则的利器。
五、类装饰器
除了函数,类也可以作为装饰器,__call__ 方法定义调用行为:
class Counter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args):
self.count += 1
return self.func(*args)
六、小结
装饰器初学可能绕,但理解"函数是对象、装饰器接收函数返回函数"后,就豁然开朗。掌握它能写出更优雅、更复用的代码。