crear una función lambda desde una cadena ** correctamente **

Dada una cadena como

"2*(i+j) <= 100" 

Quiero generar la función lambda correspondiente,

 fn = lambda i,j: 2*(i+j) <= 100 

Estaba mirando ¿Existe una biblioteca de Python para manejar conjuntos matemáticos complicados (construidos usando notación matemática de constructores de conjuntos)? y tratar de averiguar cuál es la mejor manera de analizar la notación del creador de conjuntos en las lambdas para alimentar al solucionador de restricciones.

Básicamente estoy deseando ast.literal_eval que también reconocería variables.

Idealmente, dado i >= 20 me gustaría volver ((lambda x: x >= 20), ['i']) que luego podría alimentar directamente a la constraint .

Si su entrada es de una fuente confiable , la eval () es la forma más fácil, clara y confiable de hacerlo.

Si su entrada no es de confianza , necesita ser desinfectada .

Un enfoque razonable es el uso de una expresión regular. Asegúrese de que no haya llamadas a funciones, búsquedas de atributos o guiones bajos en la cadena.

Alternativamente, un enfoque más sofisticado es recorrer el árbol de análisis AST para determinar si hay llamadas objetables.

Un tercer enfoque es recorrer el árbol de análisis AST y ejecutarlo directamente. Eso te pone en completo control sobre lo que recibe llamadas. La función ast.literal_eval toma este enfoque. Tal vez comience con su fuente y realice algunas mejoras para cualquier operación que desee apoyar:

 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) 

Estás buscando una alternativa a la eval , pero ¿por qué? Estás aceptando un código arbitrario y ejecutándolo de todos modos, ¿por qué no usar eval ? La única razón para evitar la eval es porque es peligroso, pero la lambda que terminas creando será igual de peligrosa.

Además, tenga en cuenta que realmente no puede hacer que esto sea seguro en CPython