从解析字符串创建functools.partial的*args和**kwargs
我收到了很多字符串列表,想把它们转换成方法调用,使用的是functools.partial这个工具:
[ 'object1.method1(arg1, arg2, 4, key=value)', 'object2.method2(6, arg1)' ...]
用正则表达式生成functools.partial需要的'func'参数很简单,但我在把括号里的字符串转换成有效的*args和**kwargs(也就是位置参数和关键字参数)时遇到了麻烦,没办法轻松搞定。
每个列表项都是有效的Python代码。我就是想不出一个快速简单的方法,把像'arg1, arg2, 4, key=value'这样的字符串转换成functools.partial可以使用的格式。我到底漏掉了什么呢?
更新:
抱歉,我忘了说一些重要的信息。这些参数在这个过程的范围内不是有效的标识符,所以用'eval'方法不行。不过,它们在最终使用这些部分对象的范围内是正确的,所以可以作为字面量“复制”。
我现在的做法返回的是一个字符串'arg1, arg2, 4, this=that'。如果直接传给functools.partial,它会把它当作一个单独的字符串参数来处理。
嗯……越描述我越意识到,除非这些标识符在这个范围内有效,否则是没办法做到的……
2 个回答
0
使用eval函数很简单,只需要把函数名换成你自己定义的名字,就不需要用正则表达式了。
def get_args_and_kwargs(*args, **kwargs):
return args, kwargs
def convert_str_to_args_and_kwargs(s):
return eval(s.replace(s[:s.find('(')], 'get_args_and_kwargs'))
for s in your_list:
args, kwargs = convert_str_to_args_and_kwargs(s)
2
我在写另一个回答,因为如果我改动旧的回答,评论就不会和内容匹配了。如果这个回答更好,我会撤回之前的。下面的内容应该可以工作。
操作原理:
- 获取你的函数
- 分析字符串以提取参数
- 把每个参数和它自己的评估放在一个部分中
- 把一个包装器、函数和部分参数放在另一个部分中
- 在需要的范围内执行
下面的代码主要集中在第2到第4步。假设已经导入了需要的库。当然,由于在范围内增加了额外的代码,还会有命名冲突的问题。
def wrapper(func_, *args, **kw):
new_args = []
new_kw = {}
for arg in args:
if type(arg)==functools.partial:
arg = arg()
new_args.append(arg)
for key in kw:
value = kw[key]
if type(value)==functools.partial:
value = value()
new_kw[key]=value
return func_(*new_args, **new_kw)
orig_str = 'object1.method1(arg1, arg2, 4, key=value)'
argstr = re.search('.+\((.+)\)', orig_str).group(1)
args = []
kw = {}
for x in argstr.split(','):
if '=' in x:
key, value = x.strip().split('=')
else:
value = x.strip()
key = None
value = functools.partial(eval, value)
if key:
kw[key]=value
else:
args.append(value)
what_you_want = functools.partial(wrapper, func, *args, **kw)