M
mario
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/
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/