Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert custom formula to python function [duplicate]

Consider that we have the following input

formula = "(([foo] + [bar]) - ([baz]/2) )"

function_mapping = {
                   "foo" : FooFunction,
                   "bar" : BarFunction,
                   "baz" : BazFunction,  
                  }

Is there any python library that lets me parse the formula and convert it into a python function representation.

eg.

converted_formula = ((FooFunction() + BarFunction() - (BazFunction()/2))

I am currently looking into something like

In [11]: ast = compiler.parse(formula)

In [12]: ast
Out[12]: Module(None, Stmt([Discard(Sub((Add((List([Name('foo')]), List([Name('bar')]))), Div((List([Name('baz')]), Const(2))))))]))

and then process this ast tree further.

Do you know of any cleaner alternate solution? Any help or insight is much appreciated!

like image 594
alchemist111 Avatar asked Apr 01 '16 06:04

alchemist111


1 Answers

You could use the re module to do what you want via regular-expression pattern matching and relatively straight-forward text substitution.

import re

alias_pattern = re.compile(r'''(?:\[(\w+)\])''')

def mapper(mat):
    func_alias = mat.group(1)
    function = function_alias_mapping.get(func_alias)
    if not function:
        raise NameError(func_alias)
    return function.__name__ + '()'

# must be defined before anything can be mapped to them
def FooFunction(): return 15
def BarFunction(): return 30
def BazFunction(): return 6

function_alias_mapping =  dict(foo=FooFunction, bar=BarFunction, baz=BazFunction)
formula = "(([foo] + [bar]) - ([baz]/2))"  # Custom formula.

converted_formula = re.sub(alias_pattern, mapper, formula)
print('converted_formula = "{}"'.format(converted_formula))

# define contexts and function in which to evalute the formula expression
global_context = dict(FooFunction=FooFunction,
                      BarFunction=BarFunction,
                      BazFunction=BazFunction)
local_context = {'__builtins__': None}

function = lambda: eval(converted_formula, global_context, local_context)
print('answer = {}'.format(function()))  # call function

Output:

converted_formula = "((FooFunction() + BarFunction()) - (BazFunction()/2))"
answer = 42
like image 144
martineau Avatar answered Oct 30 '22 14:10

martineau