如何在运行函数前查看装饰器参数默认值?及装饰器解耦实现
问题描述
我有一系列使用装饰器标记其在流水线中所属类别(入口、处理、出口等)的函数,示例如下:
@custom_task(task_type=TaskType.Ingress) def my_task(<arg1>, <arg2>, ...): ...
以下是custom_task装饰器的简化版本:
def custom_task(task_type=TaskType.Unknown): def wrapper(func): def executor(*args, **kwargs): func.__task_type__ = task_type func(*args, **kwargs) return executor return wrapper
我知道必须先运行代码才能创建/填充__task_type__属性,但有没有办法(使用inspect或其他库)在运行my_task前查看my_task的custom_task装饰器中task_type参数的默认值?
补充说明
实际上,该装饰器除了为函数分配枚举属性外,还包含异常日志功能,示例如下:
def custom_task(task_type=TaskType.Unknown): def wrapper(func): def executor(*args, **kwargs): try: func(*args, **kwargs) except Exception as e: # 数据库中记录异常的逻辑 ... func.__task_type__ = task_type return executor return wrapper
或许将错误日志与属性赋值行为解耦,使用两个独立装饰器会更合理?
最终解决方案
将异常日志和属性赋值的行为解耦,既能实现运行前获取__task_type__属性的需求,又能保留异常日志功能。最终实现代码如下:
使用示例
@custom_task(task_type=TaskType.Ingress) @log_exceptions def my_task(<arg1>, <arg2>, ...): ...
装饰器实现
_NO_ARG = object() def custom_task(arg=_NO_ARG): if callable(arg): func = arg func.__task_type__ = TaskType.Unknown return func if arg is _NO_ARG: task_type = TaskType.Unknown else: task_type = arg def decorator(func): func.__task_type__ = task_type return func return decorator def log_exceptions(func): def wrapper(*args, **kwargs): try: func(*args, **kwargs) except Exception as e: # 将异常记录到数据库的逻辑 ... return wrapper
方案说明
- 重构后的
custom_task不再嵌套执行器逻辑,而是在装饰阶段直接为函数绑定__task_type__属性,无需运行函数就能获取该属性值。 - 支持两种使用方式:带参数(
@custom_task(task_type=xxx))和不带参数(@custom_task),后者会默认设置task_type为TaskType.Unknown。 - 异常日志功能拆分到独立的
log_exceptions装饰器中,职责单一,方便单独复用或调整。
内容的提问来源于stack exchange,提问作者BenBole
相关产品推荐
相关产品推荐

