1

I wish to make a mathematical function ( f(x,y) in this case ) with multiple variables, only two in this case, x and y, which evaluates a mathematical expression which is in a string format initially.

For example,
If the string is

s = "2*x + sin(y) + x/(y-3.0)"

The function f(x,y) must be equivalent to

def f(x,y):
    return 2*x + sin(y) + x/(y-3.0)

The String is constant throughout the program and is initialized at the start.
The function will be called thousands of times. So I wish it to be very efficient.

What is the best way to do so?

benten
  • 1,995
  • 2
  • 23
  • 38
dark32
  • 259
  • 3
  • 14

3 Answers3

2

I'd recommend you stay away of eval and using a proper library to do the mathematical job at hands, one of the favourite candidates is sympy, which is described as:

SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python.

With sympy, you could solve your problem like this:

from sympy.parsing.sympy_parser import parse_expr

eq = parse_expr("2*x + sin(y) + x/(y-3.0)")

for x in range(4):
    for y in range(4):
        s1 = eq.subs({"x": x, "y": y})
        s2 = s1.evalf()
        print s1, "-->", s2

Output:

0 --> 0
sin(1) --> 0.841470984807897
sin(2) --> 0.909297426825682
sin(3) --> 0.141120008059867
1.66666666666667 --> 1.66666666666667
sin(1) + 1.5 --> 2.34147098480790
sin(2) + 1.0 --> 1.90929742682568
zoo --> zoo
3.33333333333333 --> 3.33333333333333
sin(1) + 3.0 --> 3.84147098480790
sin(2) + 2.0 --> 2.90929742682568
zoo --> zoo
5.00000000000000 --> 5.00000000000000
sin(1) + 4.5 --> 5.34147098480790
sin(2) + 3.0 --> 3.90929742682568
zoo --> zoo

zoo means "complex infinity". For more info, read the docs.

Of course, you could use one of the many existing python parsers out there or just writing yours as suggested by vz0. I'd recommend you learn more about sympy though.

BPL
  • 9,632
  • 9
  • 59
  • 117
  • Sympy uses `eval` under the hood, so this is not safer; see https://github.com/sympy/sympy/issues/10805 – kaya3 Jan 13 '20 at 17:38
1

Without using SymPy you should create your own parser, for example by converting the infix expression to a postfix expression, which are very easy to evaluate once in this notation. Mathematical functions are just unary operators like -x.

Community
  • 1
  • 1
vz0
  • 32,345
  • 7
  • 44
  • 77
-5

Use the eval function return eval(s)

  • 5
    And make sure to surround it with `try ... except` to catch the many horrible errors that might occur – holdenweb Sep 13 '16 at 14:57
  • 5
    And make sure the input is 100% safe – Dunno Sep 13 '16 at 14:57
  • 3
    Plus you might need to ensure that the evaluation takes place with the right namespaces for locals and globals – holdenweb Sep 13 '16 at 14:58
  • Yes, I had that in mind already, but eval(s) will evaluate the string every time the function is called. Considering the function will be called thousands of time. Is there something more efficient? – dark32 Sep 13 '16 at 15:00
  • @dark32 Structure your script differently so that you don't make the same calculations 1000s of times. E.g. store the string and output in a dictonary as key/value pairs and look it up before computing. – Steinar Lima Sep 13 '16 at 15:17
  • @Alvaro Marques Most of the time, the arguments given will be different. – dark32 Sep 13 '16 at 15:27