从字符串“正确地"创建一个lambda函数 [英] create a lambda function from a string **properly**
问题描述
给出一个字符串,例如
"2*(i+j) <= 100"
我想生成相应的lambda函数,
I want to generate the corresponding lambda function,
fn = lambda i,j: 2*(i+j) <= 100
-
我可以用
eval
做到这一点,但是我正在寻找一种不太邪恶的方法.I can do this with
eval
, but I am seeking a less evil method.我找到了
import ast f = ast.Lambda('i,j', '2*(i+j) <= 100')
但是我还没有弄清楚如何执行结果!
but I haven't figure out how to execute the result!
理想情况下,我也想自动提取参数列表('i','j')-现在,我只是使用re.findall('\ w +'),但我会喜欢能够正确使用
cos
之类的现有功能,而不是将它们隐藏为关键字".Ideally, I would like to automatically pull out the parameter list ('i','j') as well - right now, I am just using re.findall('\w+'), but I would love to be able to properly use existing functions like
cos
instead of shadowing them as 'keywords'.我正在查看是否存在并尝试找出如何最好地将set-builder表示法解析为lambda以便馈送给约束求解器的Python库用于处理复杂的数学集(使用数学set-builder表示法构建).
I was looking at Is there a Python library for handling complicated mathematical sets (constructed using mathematical set-builder notation)? and trying to figure out how best to parse the set-builder notation into the lambdas to feed to the constraint-solver.
我基本上希望ast.literal_eval也可以识别变量.
I'm basically wishing for ast.literal_eval which would also recognize variables.
理想情况下,考虑到
i >= 20
,我想找回((lambda x: x >= 20), ['i'])
,然后我可以直接将其喂入constraint
.Ideally, given
i >= 20
I would like to get back((lambda x: x >= 20), ['i'])
which I could then feed directly toconstraint
.推荐答案
如果您的输入来自受信任的来源,则 eval()是最简单,最清晰的,也是最可靠的方法.
If your input is from a trusted source, the eval() is the easiest, clearest, and most reliable way to go.
如果您输入的内容不受信任,则需要对其进行清理.
If your input is untrusted, then it needs to be sanitized.
一种合理的方法是使用正则表达式.确保字符串中没有函数调用,属性查找或双下划线.
One reasonable approach is the use of a regex. Make sure there are no function calls, attribute lookups, or double underscores in the string.
或者,一种更复杂的方法是遍历AST解析树以确定是否有任何令人反感的呼叫.
Alternatively, a more sophisticated approach is to walk the AST parse tree to determine whether there are any objectionable calls.
第三种方法是遍历AST解析树并直接执行它.这样一来,您就可以完全控制收到电话的内容. ast.literal_eval函数采用这种方法.也许您从其源代码开始,并对要支持的任何操作进行一些扩展:
A third approach is to walk the AST parse tree and execute it directly. That puts you in complete control over what gets calls. The ast.literal_eval function takes this approach. Perhaps you start with its source and do some buildouts for any operations you want to support:
def literal_eval(node_or_string): """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None. """ _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, basestring): node_or_string = parse(node_or_string, mode='eval') if isinstance(node_or_string, Expression): node_or_string = node_or_string.body def _convert(node): if isinstance(node, Str): return node.s elif isinstance(node, Num): return node.n elif isinstance(node, Tuple): return tuple(map(_convert, node.elts)) elif isinstance(node, List): return list(map(_convert, node.elts)) elif isinstance(node, Dict): return dict((_convert(k), _convert(v)) for k, v in zip(node.keys, node.values)) elif isinstance(node, Name): if node.id in _safe_names: return _safe_names[node.id] elif isinstance(node, BinOp) and \ isinstance(node.op, (Add, Sub)) and \ isinstance(node.right, Num) and \ isinstance(node.right.n, complex) and \ isinstance(node.left, Num) and \ isinstance(node.left.n, (int, long, float)): left = node.left.n right = node.right.n if isinstance(node.op, Add): return left + right else: return left - right raise ValueError('malformed string') return _convert(node_or_string)
这篇关于从字符串“正确地"创建一个lambda函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!