如何检测Python函数所应用的装饰器(基于functools.wraps)
解决方案
由于Python默认不会自动记录应用在函数上的装饰器信息——即便是使用functools.wraps,也仅会维护__wrapped__属性指向被包装的原函数。要实现获取装饰器列表或判断是否被特定装饰器装饰的功能,需要手动给装饰器添加标识,再通过遍历__wrapped__链来收集信息。
实现步骤
1. 给装饰器添加标识
我们可以给每个装饰器返回的包装器函数绑定一个属性,指向装饰器本身。为了避免重复代码,推荐写一个通用的标记装饰器:
from functools import wraps # 通用装饰器,用于给目标装饰器添加标识 def mark_decorator(decorator): def wrapper(func): wrapped_func = decorator(func) # 给包装器绑定对应的装饰器引用 wrapped_func.__decorator__ = decorator return wrapped_func return wrapper
然后用这个标记装饰器修饰你的自定义装饰器:
@mark_decorator def decorator_wraps_1(function): @wraps(function) def _wrapper(*a, **kw): return function(*a, **kw) return _wrapper @mark_decorator def decorator_wraps_2(function): @wraps(function) def _wrapper(*a, **kw): return function(*a, **kw) return _wrapper
如果不想用通用标记,也可以直接在每个装饰器内部手动添加属性,效果完全一致:
def decorator_wraps_1(function): @wraps(function) def _wrapper(*a, **kw): return function(*a, **kw) _wrapper.__decorator__ = decorator_wraps_1 return _wrapper
2. 实现装饰器列表获取与检查函数
通过遍历函数的__wrapped__链,收集所有绑定的装饰器:
def decorators(func): decorator_list = [] current_func = func # 遍历包装链,直到没有__wrapped__属性 while hasattr(current_func, '__wrapped__'): # 如果当前包装器有装饰器标识,加入列表 if hasattr(current_func, '__decorator__'): decorator_list.append(current_func.__decorator__) # 跳转到下一层被包装的函数 current_func = current_func.__wrapped__ return decorator_list def is_decorated_by(func, decorator): # 检查目标装饰器是否在装饰器列表中 return decorator in decorators(func)
3. 测试验证
@decorator_wraps_1 @decorator_wraps_2 def foo(x, y): return x + y # 获取装饰器名称列表 print([d.__name__ for d in decorators(foo)]) # 输出: ['decorator_wraps_1', 'decorator_wraps_2'] # 检查是否被指定装饰器装饰 print(is_decorated_by(foo, decorator_wraps_1)) # 输出: True print(is_decorated_by(foo, decorator_wraps_2)) # 输出: True
注意事项
- 该方案仅适用于你能控制的自定义装饰器,第三方装饰器需要看是否提供了类似的标识,或者通过包装第三方装饰器来添加
__decorator__属性。 - 依赖
functools.wraps维护的__wrapped__属性,这是Python官方文档明确的公共属性,不存在内部实现变更的风险。 - 装饰器的列表顺序与代码中
@的顺序一致(最外层装饰器在前),符合调用时的触发顺序。
内容的提问来源于stack exchange,提问作者MattSom
相关产品推荐
相关产品推荐

