从YAML文件传递Python函数

2024-04-25 22:58:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个YAML脚本,用户可以在其中定义一些参数。它们还可以在YAML文件中声明要应用的自定义函数。例如:

processes:
    args1: 10
    args2: 5
    funct: np.sum

此YAML将传递给如下函数:

def custom_func(args1, args2, funct):
    return funct(args1, args2)

对于上面的YAML示例,我希望custom_func()执行np.sum(10,5)。如何将YAML文件中的数据解析为可调用的eval()可能会执行此操作,但可能存在安全问题。有什么合适的方法吗?谢谢


Tags: 文件函数用户脚本声明yaml参数定义
2条回答

是的,evalexec都是坏习惯。很高兴你知道:D

你可以用字典来做这件事。 您可以做的是定义一个字典,并使键成为YAML中的funct值。该值将是一个未调用的函数。这类似于一个变量

funct_parser = {
    "np.sum": np.sum # Notice how this doesn't have ()
}

然后可以对字典使用funct来调用适当的方法。如下所示:

def custom_func(args1, args2, funct):
    my_func = funct_parser[str(funct)] # This will cause my_func to be a copy of `np.sum`.
    return my_func(args1, args2) # Call my_func

顺便说一句,你真的不必在多行上做custom_func,我这样做只是为了更好地解释它

备选方案:
如果您不想硬编码字典中的每个部分,可以使用^{}

# This code assumes you have numpy imported as np (You can always change it)
def custom_func(args1, args2, funct):
    funct = funct.split("np.")[0] # Will work for np. You can always change to other modules when needed.
    return getattr(np, funct)

您还可以根据函数的Python点路径加载该函数

但是,这只获取函数并调用它,它不会试图找出调用签名,即np.sum([5,10]),而不是np.sum(10,5)

from yaml import safe_load as yload
from importlib import import_module

def load_func(dotpath : str):
    """ load function in module.  function is right-most segment """
    module_, func = dotpath.rsplit(".", maxsplit=1)
    m = import_module(module_)
    return getattr(m, func)
    
yaml = """
processes:
    args1: 10
    args2: 5

    #gotta give real package name, not `np`
    funct: numpy.sum
"""

di = yload(yaml)
pr = di["processes"]
func = load_func(pr["funct"])
array = [pr["args1"], pr["args2"]]

print (f"{func=} {func(array)=}")

输出:

func=<function sum at 0x106645e50> func(array)=15

相关问题 更多 >