Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Way to speed up a repeatedly executed eval statement?

Tags:

In my code, I'm using eval to evaluate a string expression given by the user. Is there a way to compile or otherwise speed up this statement?

import math import random  result_count = 100000 expression = "math.sin(v['x']) * v['y']"  variable = dict() variable['x'] = [random.random() for _ in xrange(result_count)] variable['y'] = [random.random() for _ in xrange(result_count)]  # optimize anything below this line  result = [0] * result_count  print 'Evaluating %d instances of the given expression:' % result_count print expression  v = dict() for index in xrange(result_count):     for name in variable.keys():         v[name] = variable[name][index]     result[index] = eval(expression) # <-- option ONE     #result[index] = math.sin(v['x']) * v['y'] # <-- option TWO 

For a quick comparison option ONE takes 2.019 seconds on my machine, while option TWO takes only 0.218 seconds. Surely Python has a way of doing this without hard-coding the expression.

like image 670
devtk Avatar asked Sep 17 '12 21:09

devtk


People also ask

What can I use instead of eval in python?

literal_eval may be a safer alternative. literal_eval() would only evaluate literals, not algebraic expressions.

Is eval good practice python?

eval() is considered insecure because it allows you (or your users) to dynamically execute arbitrary Python code. This is considered bad programming practice because the code that you're reading (or writing) is not the code that you'll execute.

What does eval () do in python?

Python eval() Function The eval() function evaluates the specified expression, if the expression is a legal Python statement, it will be executed.

What is the difference between eval and int in python?

eval evaluates any python code. int tries to convert any type to integer (float, bool, string ...). you got it.


2 Answers

You can also trick python:

expression = "math.sin(v['x']) * v['y']" exp_as_func = eval('lambda: ' + expression) 

And then use it like so:

exp_as_func() 

Speed test:

In [17]: %timeit eval(expression) 10000 loops, best of 3: 25.8 us per loop  In [18]: %timeit exp_as_func() 1000000 loops, best of 3: 541 ns per loop 

As a side note, if v is not a global, you can create the lambda like this:

exp_as_func = eval('lambda v: ' + expression) 

and call it:

exp_as_func(my_v) 
like image 181
Ohad Avatar answered Sep 27 '22 18:09

Ohad


You can avoid the overhead by compiling the expression in advance using compiler.compile() for Python 2 or compile() for Python 3 :

In [1]: import math, compiler  In [2]: v = {'x': 2, 'y': 4}  In [3]: expression = "math.sin(v['x']) * v['y']"  In [4]: %timeit eval(expression) 10000 loops, best of 3: 19.5 us per loop  In [5]: compiled = compiler.compile(expression, '<string>', 'eval')  In [6]: %timeit eval(compiled) 1000000 loops, best of 3: 823 ns per loop 

Just make sure you do the compiling only once (outside of the loop). As mentioned in comments, when using eval on user submitted strings make sure you are very careful about what you accept.

like image 37
Andrew Clark Avatar answered Sep 27 '22 19:09

Andrew Clark