如何在不使用inspect模块的情况下移除函数签名中的绑定参数?
不使用inspect模块移除函数默认参数的实现方案
核心思路
避开修改函数元数据的方式,通过动态生成仅接受必填参数的包装函数解决问题:先利用Python调用函数时的错误提示,提取绑定指定参数后剩余的必填参数,再通过exec生成签名匹配的包装器,内部调用绑定后的原函数。
实现代码
from functools import partial def _get_required_args(func): try: func() except TypeError as err: err_msg = str(err) # 处理单个必填参数的场景 if "required positional argument" in err_msg: return [err_msg.split("'")[1]] # 处理多个必填参数的场景 elif "required positional arguments" in err_msg: # 从错误信息中解析出参数名 arg_parts = err_msg.split("'") return [arg_parts[i] for i in range(1, len(arg_parts), 2)] return [] def remove_default_args(func, **kwargs): # 先绑定用户指定的参数到原函数 bound_func = partial(func, **kwargs) # 获取绑定后函数的必填参数列表 required_args = _get_required_args(bound_func) # 动态生成仅接受必填参数的包装函数代码 wrapper_code = f""" def wrapper({', '.join(required_args)}): return bound_func({', '.join(required_args)}) """ local_namespace = {} # 执行代码生成包装函数 exec(wrapper_code, {"bound_func": bound_func}, local_namespace) return local_namespace["wrapper"]
使用示例
假设外部库的函数如下:
# 模拟外部库带默认参数的函数 def bar1(a, b=10, c=20): return a + b + c def bar2(x, y="hello", z=True): return f"{x}-{y}-{z}"
使用包装函数适配:
# 直接包装,保留原函数必填参数 wrapped_bar1 = remove_default_args(bar1) print(wrapped_bar1(5)) # 输出:35(5+10+20) # 绑定部分参数后包装,仅剩余必填参数 wrapped_bar1_custom = remove_default_args(bar1, b=5) print(wrapped_bar1_custom(5)) # 输出:30(5+5+20) # 适配另一个外部函数 wrapped_bar2 = remove_default_args(bar2) print(wrapped_bar2("test")) # 输出:test-hello-True
这个方案完全不需要依赖inspect模块,生成的包装函数签名仅包含必填参数,能直接满足foo的调用要求,同时批量处理100个外部函数也非常方便。
内容的提问来源于stack exchange,提问作者Ilya Kuleshov
相关产品推荐
相关产品推荐

