如何解决带有 getattr 和 args/kwargs 的 Python 调用函数
我想从这样的字符串中调用带有 getattr
(或者其他东西?)的模块函数:
import bar
funcStr = "myFunc(\"strParam\",123,bar.myenum.val1,kwarg1=\"someString\",kwarg2=456,kwarg3=bar.myenum.val2)"
[function,args,kwargs] = someParsingFunction(funcStr)
# call module function
getattr(bar,function)(*args,**kwargs)
如何从字符串中提取 args
和 kwargs
,以便将它们传递给 getattr
?
我尝试了 literal_eval
方法与 pythons ast
模块。但是 ast
无法评估模块 bar
的枚举。 SO 上的所有其他示例都传递一个 kwargs
映射,其中仅包含字符串。他们尤其从不解析字符串中的参数。还是有其他方法可以直接从字符串中调用函数?
编辑: python 脚本从文件中读取函数字符串。因此不建议在此处使用 eval
。
EDIT2:使用 python 3.6.3
EDIT3:感谢前两个答案,我想出了两个想法。从输入字符串中解析出 args
和 kwargs
后,有两种方法可以获得正确类型的参数。
- 我们可以使用
ast.literal_eval(<value of the argument>)
。对于像kwarg2
中的标准类型的参数,它将返回所需的值。如果这除外,这将发生在枚举中,那么我们将在getattr
模块上使用bar
并获取枚举。如果这也是例外,则字符串无效。 - 我们可以使用
inspect
模块并遍历myFunc
的参数。然后对于每个arg
和kwarg
,我们将检查该值是否是myFunc
参数(类型)的实例。如果是这样,我们会将 arg/kwarg 转换为myFunc
参数类型。否则我们会引发异常,因为给定的 arg/kwarg 不是myFunc
参数的实例。这个解决方案比第一个更灵活。
这两种解决方案都更像是一种解决方法。第一次测试似乎有效。我稍后会在这里发布我的结果。
解决方法
这有帮助吗?
funcStr = r"""myFunc(\"strParam\",123,bar.myenum.val1,kwarg1=\"someString\",kwarg2=456,kwarg3=bar.myenum.val2)"""
def someParsingFunction(s):
func,s1 = s.split('(',1)
l = s1.replace('\\','').strip(')').split(',')
arg_ = [x.strip('"') for x in l if '=' not in x]
kwarg_ = {x.split('=')[0]:x.split('=')[-1] for x in l if '=' in x}
return func,arg_,kwarg_
class bar:
def myFunc(self,*args,**kwargs):
print(*args)
print(kwargs)
[function,args,kwargs] = someParsingFunction(funcStr)
getattr(bar,function)(*args,**kwargs)
# 123 bar.myenum.val1
# {'kwarg1': '"someString"','kwarg2': '456','kwarg3': 'bar.myenum.val2'}
替代
funcStr = r"""myFunc(\"strParam\",bar.val1,kwarg3=bar.val2)"""
def someParsingFunction(s):
func,kwarg_
class Bar:
def __init__(self):
self.val1 = '111'
[function,kwargs] = someParsingFunction(funcStr)
bar = Bar()
obj_name = 'bar' + '.'
args = [bar.__getattribute__(x.split(obj_name)[-1]) if x.startswith(obj_name) else x for x in args]
print(args)
,
def get_bar_args(arg_str):
"""
example:
arg_str='bar.abc.def'
assumess 'bar' module is imported
"""
from functools import reduce
reduce(getattr,arg_str.split('.')[1:],bar)
def parseFuncString(func_str):
'''
example: func_str = "myFunc(\"strParam\",kwarg3=bar.myenum.val2)"
'''
import re
all_args_str = re.search("(.*)\((.*)\)",func_str)
all_args = all_args_str.group(2).split(',')
all_args = [x.strip() for x in all_args]
kwargs = {kw.group(1): kw.group(2) for x in all_args if (kw:=re.search('(^\w+)=(.*)$',x))}
pargs = [x for x in all_args if not re.search('(^\w+)=(.*)$',x)]
pargs = [get_bar_args(x) if x.startswith('bar.') else x for x in pargs]
kwargs = {k: get_bar_args(v) if v.startswith('bar.') else v for k,v in kwargs.items()}
print(f'{all_args=}\n{kwargs=}\n{pargs=}')
func_name = func_str.split("(")[0]
return func_name,pargs,kwargs
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。