Ideas to optimize this getitem/eval call?

mario mario.ruggier at gmail.com
Sat Jan 3 02:29:29 CET 2009


Hi,

below is the essence of a an expression evaluator, by means of a
getitem lookup. The expression codes are compiled and cached -- the
lookup is actually recursive, and the first time around it will always
fail.

import sys
class GetItemEval(object):

    def __init__(self):
        self.globals = globals() # some dict (always the same)
        self.locals = {} # some other dict (may be different between
evaluations)
        self.codes = {} # compiled code expressions cache

    def __getitem__(self, expr):
        try:
            return eval(self.codes[expr], self.globals, self.locals)
        except:
            # KeyError, NameError, AttributeError, SyntaxError,
ValueError,
            # TypeError, IOError
            #
            # Special case if a KeyError is coming from the self.codes
[name]
            # lookup (traceback should consist of a single frame
only):
            if sys.exc_info()[2].tb_next is None:
                if sys.exc_info()[0] is KeyError:
                    self.codes[expr] = compile(expr, '<string>',
'eval')
                    return self[expr]
            # otherwise handle eval error in some way...

This class could be used in a way as follows:

# define some expressions
def f(s): return "["+s+"]"
exprs = ["1+2+3", "2*3*5", "f(__name__)"]
# instantiate one
gie = GetItemEval()
# use it to lookup/eval each expression
for x in exprs:
    print x, "=", gie[x]

And, fwiw, some sample timeit code:

import timeit
print timeit.Timer("for x in exprs: gie[x]",
        "from __main__ import gie, exprs").timeit(500000)

I had done various poking to discover if it could be made to go
faster, and in the end I settled on the version above.

mario

Incidentally this constitutes the lion's share of the evaluation
runtime of evoque templating... http://evoque.gizmojo.org/



More information about the Python-list mailing list