如何实现接收参数名列表的make_function函数(规避eval用法)
替代eval的实现方案
你的eval实现确实存在调试不便、依赖函数名查找的问题,这里提供两种更安全可靠的替代方案:
方案一:闭包+自定义签名(推荐)
利用Python的闭包特性直接捕获inner_func对象,避免字符串形式的函数名查找,同时可以通过inspect模块自定义函数签名,让新函数的参数名符合要求:
from typing import List, Callable import inspect def make_function(arg_names: List[str], inner_func: Callable): def wrapper(*args, **kwargs): # 可选:添加参数校验,确保传入的参数与arg_names匹配 # if len(args) > len(arg_names): # raise TypeError(f"expected at most {len(arg_names)} positional arguments, got {len(args)}") # for kw in kwargs: # if kw not in arg_names: # raise TypeError(f"unexpected keyword argument: '{kw}'") return inner_func(*args, **kwargs) + 5 # 自定义函数签名,让新函数的参数名显示为arg_names指定的内容 params = [ inspect.Parameter(name, inspect.Parameter.POSITIONAL_OR_KEYWORD) for name in arg_names ] wrapper.__signature__ = inspect.signature(wrapper).replace(parameters=params) return wrapper
优势:
- 直接捕获
inner_func对象,不会出现环境中找不到函数名的问题 - 调试方便,可以直接在
wrapper函数内添加断点或日志 - 可选添加参数校验,增强鲁棒性
方案二:使用exec生成函数(适合需要严格参数签名的场景)
如果需要完全匹配指定参数名的函数签名(比如通过help()查看时显示准确参数),可以用exec动态生成函数,但需确保arg_names是可信的输入:
from typing import List, Callable import functools def make_function(arg_names: List[str], inner_func: Callable): args_str = ", ".join(arg_names) local_scope = {} # 生成函数定义的字符串并执行 exec(f"def new_func({args_str}): return inner_func({args_str}) + 5", globals(), local_scope) new_func = local_scope["new_func"] # 将inner_func绑定到函数的闭包,避免后续名字查找问题 functools.update_wrapper(new_func, inner_func) return new_func
注意事项:
- 仅当
arg_names来自可信来源时使用,避免注入风险 - 生成的函数签名完全符合指定的参数名,行为与你原来的eval版本一致
内容的提问来源于stack exchange,提问作者soap
相关产品推荐
相关产品推荐

