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

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


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 loopIn [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)


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, compilerIn [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 loopIn [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.


I think you are optimising the wrong end. If you want to perform the same operation for a lot of numbers you should consider using numpy:

import numpyimport timeimport mathimport randomresult_count = 100000expression = "sin(x) * y"namespace = dict(    x=numpy.array(        [random.random() for _ in xrange(result_count)]),    y=numpy.array(        [random.random() for _ in xrange(result_count)]),    sin=numpy.sin,)print ('Evaluating %d instances '       'of the given expression:') % result_countprint expressionstart = time.time()result = eval(expression, namespace)numpy_time = time.time() - startprint "With numpy:", numpy_timeassert len(result) == result_countassert all(math.sin(a) * b == c for a, b, c in           zip(namespace["x"], namespace["y"], result))

To give you an idea about the possible gain I've added a variant using generic python and the lambda trick:

from math import sinfrom itertools import izipstart = time.time()f = eval("lambda: " + expression)result = [f() for x, y in izip(namespace["x"], namespace["y"])]generic_time = time.time() - startprint "Generic python:", generic_timeprint "Ratio:", (generic_time / numpy_time)

Here are the results on my aging machine:

$ python speedup_eval.py Evaluating 100000 instances of the given expression:sin(x) * yWith numpy: 0.006098985672Generic python: 0.270224094391Ratio: 44.3063992807

The speed-up is not as high as I expected, but still significant.