我会遵循Python之禅中的特定原则,尤其是“显式优于隐式”和“可读性至上”。
因此,将函数作为可读字符串定义lambda表达式是一个好主意,但是出于安全原因,在加载的lambda字符串表示上调用eval可能不是一个好主意。这取决于谁有修改文件访问权限以及他们在哪个系统上运行。
通常情况下,如果某人具有登录访问权限,则不必过于关心是否可以(非故意地)注入某些内容导致递归删除系统上的所有文件。 但是,如果例如软件运行在远程系统上并且可以通过某些Web界面编辑这些文件,或者如果文件更改可以由其他人而不是使用文件的人进行,则应考虑这一点。
如果lambda来自固定集合,则可以将其字符串表示用作查找。
lambdas = {}
for l in [
'lambda x,y: x+y',
'lambda x: (x**3)/2',
]:
lambdas[l] = eval(l)
你可以使用从配置YAML加载的字符串来获取实际的lambda表达式,该字符串无法被篡改,因为它必须与您提供的可用lambda表达式集合匹配。当然,您可以从只有您可以更改的文件中加载实际的lambda字符串,而不是在源代码中硬编码它们。
这比转储实际的lambda表达式并生成类似YAML的输出更加明确。
!!python/name:__main__.%3Clambda%3E
如果你需要更灵活的方式,而不是使用预定义的lambda表达式,但又不想使用eval的不安全性,那么另一个可能性是使用Python的AST模块。该模块允许对一元和二元运算符进行安全评估,但可以扩展为仅处理您想要在lambda中允许的函数(例如某些数学函数)。我在我的Python对象表示法模块中做了类似的扩展(PON),添加了日期时间和去除缩进的功能到AST评估输入中。
我认为您应该改进一下您的YAML。不要使用gene1
,gene2
作为映射中的键,而是使用序列并标记项目:
pre_init_gene:
- !Gene 1.0
- !Gene 1.0
- !Gene 1.0
或者,另一种方法是标记这个序列:
pre_init_gene: !Genes
- 1.0
- 1.0
- 1.0
你的lambda表达式存在相同的“问题”,我会这样做:
obj_funcs:
- !Lambda 'x, y: x+y'
- !Lambda 'x: (x**3)/2'
实现from_yaml
classmethod
的对象会自动执行eval或AST评估,用于标签!Lambda
。
obj_funcs: {obj_fun1: "functions.function_one", ...}
来实现的。 - Adam Smith