如何编写可作为模块使用的Python函数合并函数?
解决函数合并后无法跨模块调用的问题
问题根源
你之前用inspect+eval的实现无法跨模块调用,核心原因是eval生成的函数会绑定到执行eval的模块命名空间,其__module__属性与原函数f、g的模块不一致,跨模块导入后会出现找不到函数引用的问题。
替代实现(支持跨模块调用)
无需依赖eval,直接通过inspect获取参数签名,结合包装函数与元数据修正,就能实现符合要求的函数合并:
import inspect import functools def merge_functions(f, g): # 获取原函数的参数签名(假设f和g参数兼容,需校验可自行添加逻辑) sig = inspect.signature(f) params = list(sig.parameters.values()) @functools.wraps(f) def merged_func(*args, **kwargs): # 绑定参数并校验合法性 bound_args = sig.bind(*args, **kwargs) bound_args.apply_defaults() # 依次调用f和g f(*bound_args.args, **bound_args.kwargs) g(*bound_args.args, **bound_args.kwargs) # 显式设置参数签名,保留原函数的参数名称与结构 merged_func.__signature__ = sig # 修正模块属性,确保跨模块导入时的命名空间正确 merged_func.__module__ = f.__module__ if hasattr(f, '__module__') else __name__ return merged_func
关键细节说明
- 参数签名保留:通过
inspect.signature获取原函数的参数结构,再给合并后的函数设置__signature__属性,保证调用时的参数提示与原函数一致。 - 模块属性修正:手动设置
__module__为原函数f的模块,避免跨模块导入时出现函数引用失效的问题。 - 兼容性处理:
functools.wraps会自动继承原函数的__name__、__doc__等元数据,让合并后的函数更贴近原生定义。
扩展:处理f和g参数不一致的情况
如果f和g的参数签名不同,可通过合并两者的参数列表实现兼容:
def merge_functions(f, g): sig_f = inspect.signature(f) sig_g = inspect.signature(g) # 合并参数(去重,保留顺序) merged_params = list(sig_f.parameters.values()) for name, param in sig_g.parameters.items(): if name not in sig_f.parameters: merged_params.append(param) merged_sig = inspect.Signature(parameters=merged_params) @functools.wraps(f) def merged_func(*args, **kwargs): bound_args = merged_sig.bind(*args, **kwargs) bound_args.apply_defaults() # 调用f时只传递它接受的参数 f_args = {k: v for k, v in bound_args.arguments.items() if k in sig_f.parameters} f(**f_args) # 调用g时只传递它接受的参数 g_args = {k: v for k, v in bound_args.arguments.items() if k in sig_g.parameters} g(**g_args) merged_func.__signature__ = merged_sig merged_func.__module__ = f.__module__ if hasattr(f, '__module__') else __name__ return merged_func
内容的提问来源于stack exchange,提问作者float
相关产品推荐
相关产品推荐

