如何实现可向被装饰函数传递可选关键字参数的Python装饰器
Python 可选参数传递装饰器实现方案
原有捕捉 TypeError 的实现存在明显缺陷:
- 会误拦截函数内部抛出的 TypeError 异常
- 依赖异常信息字符串匹配,不同语言环境、Python版本的异常提示存在差异,兼容性差
最优实现思路
使用 Python 标准库的 inspect 模块检测被装饰函数的参数签名,判断函数是否支持接收目标关键字参数,再决定是否传入参数。
基础实现代码
import inspect from functools import wraps def mydecorator(fn): @wraps(fn) # 保留原函数的元信息(函数名、文档字符串等) def wrapper(*args, **kwargs): # 定义要传递的可选关键字参数,可根据需求修改 optional_params = {"magic_word": "Abracadabra!"} # 获取被装饰函数的参数签名 sig = inspect.signature(fn) func_params = sig.parameters # 筛选出函数可接收的参数 pass_params = {} for k, v in optional_params.items(): # 两种情况可以传参数:1.函数显式定义了该参数 2.函数定义了**kwargs接收任意关键字参数 if k in func_params or any(p.kind == inspect.Parameter.VAR_KEYWORD for p in func_params.values()): pass_params[k] = v # 合并参数,调用方传入的kwargs优先级更高 final_kwargs = {**pass_params, **kwargs} return fn(*args, **final_kwargs) return wrapper
测试效果
@mydecorator def dummy_without_magic_word(): print('hello world') @mydecorator def dummy_with_magic_word(magic_word): print(magic_word) dummy_without_magic_word() # 输出:hello world dummy_with_magic_word() # 输出:Abracadabra!
扩展灵活版本
如果需要在装饰器使用时动态指定要传递的可选参数,可以嵌套一层实现参数化装饰器:
import inspect from functools import wraps def mydecorator(**optional_params): def decorator(fn): @wraps(fn) def wrapper(*args, **kwargs): sig = inspect.signature(fn) func_params = sig.parameters pass_params = {} for k, v in optional_params.items(): if k in func_params or any(p.kind == inspect.Parameter.VAR_KEYWORD for p in func_params.values()): pass_params[k] = v final_kwargs = {**pass_params, **kwargs} return fn(*args, **final_kwargs) return wrapper return decorator
扩展版本使用示例
# 装饰时指定要传入的参数值 @mydecorator(magic_word="Hocus Pocus!", other_param=123) def dummy_with_magic_word(magic_word): print(magic_word) dummy_with_magic_word() # 输出:Hocus Pocus!
内容的提问来源于stack exchange,提问作者theahura
相关产品推荐
相关产品推荐

