Python 装饰器
Python 装饰器详解
装饰器(Decorator)是 Python 中一种在不修改原函数代码的前提下,给函数增加额外功能的语法特性。本质上就是一个接收函数、返回函数的函数。
1. 核心思想
函数在 Python 中是一等公民——可以赋值给变量、作为参数传递、作为返回值。装饰器就建立在这个基础上:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("函数执行前")
result = func(*args, **kwargs)
print("函数执行后")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}")
say_hello("Alice")
# 等价于: say_hello = my_decorator(say_hello)
输出:
函数执行前
Hello, Alice
函数执行后
@ 语法只是语法糖,@my_decorator 就是执行 say_hello = my_decorator(say_hello)。
2. 常见应用场景
计时器
import time
from functools import wraps
def timer(func):
@wraps(func) # 保留原函数的 __name__、__doc__ 等元信息
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.perf_counter() - start:.4f}s")
return result
return wrapper
日志 / 权限校验 / 缓存
def require_login(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.get("logged_in"):
raise PermissionError("请先登录")
return func(user, *args, **kwargs)
return wrapper
3. 带参数的装饰器(三层嵌套)
装饰器本身接受参数时,需要再多包一层:
def repeat(times): # 1. 接收装饰器参数
def decorator(func): # 2. 接收函数
@wraps(func)
def wrapper(*args, **kwargs): # 3. 真正执行
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet():
print("hi")
4. 类装饰器
通过实现 __call__ 让类的实例可以像函数一样被调用:
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"第 {self.count} 次调用")
return self.func(*args, **kwargs)
@CountCalls
def ping():
return "pong"
适合需要维护状态的场景(调用计数、缓存等)。
5. 内置装饰器速览
| 装饰器 | 作用 |
|---|---|
@staticmethod |
静态方法,不需要实例 |
@classmethod |
类方法,第一个参数是 cls |
@property |
把方法变成属性访问 |
@functools.lru_cache |
自动缓存函数结果 |
@functools.wraps |
装饰器内部使用,保留原函数元信息 |
@dataclasses.dataclass |
自动生成 __init__ 等 |
6. 关键注意点
- 一定要用
@functools.wraps(func),否则被装饰后的函数会丢失__name__、__doc__,影响调试和文档生成。 - 装饰器在定义时(import 时)就执行,而不是函数调用时——所以装饰器不适合包裹“延迟执行”的逻辑。
- 多个装饰器的执行顺序是从下往上:
@a @b def f(): ... # 等价于 f = a(b(f)),b 先包裹,a 后包裹 - 装饰器也可以装饰类(如
@dataclass)甚至用类装饰整个类。
一句话总结
装饰器 = 用函数(或类)包装函数(或类),配合
@语法实现横切关注点(日志、缓存、鉴权、计时)与业务逻辑的解耦,是 Python 中最优雅的代码复用手段之一。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 恒星不见
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果

