S
sturlamolden
Hello
The Lisp crowd always brags about their magical macros. I was
wondering if it is possible to emulate some of the functionality in
Python using a function decorator that evals Python code in the stack
frame of the caller. The macro would then return a Python expression
as a string. Granted, I know more Python than Lisp, so it may not work
exactly as you expect.
Any comments and improvements are appreciated.
Regards,
Sturla Molden
__codestore__ = {}
def macro(func):
"""
Lisp-like macros in Python
(C) 2007 Sturla Molden
@macro decorates a function which must return a Python
expression
as a string. The expression will be evaluated in the context
(stack frame)
of the caller.
"""
def macro_decorator(*args,**kwargs):
global __codestore__
import sys
pycode = '(' + func(*args,**kwargs) + ')'
try:
ccode = __codestore__[pycode]
except:
ccode = compile(pycode,'macrostore','eval')
__codestore__[pycode] = ccode
frame = sys._getframe().f_back
try:
retval = eval(ccode,frame.f_globals,frame.f_locals)
return retval
except:
raise
macro_decorator.__doc__ = func.__doc__
return macro_decorator
# Usage example
def factorial(x):
""" computes the factorial function using macro expansion """
@macro
def fmacro(n):
""" returns '1' or 'x*(x-1)*(x-2)*...*(x-(x-1))' """
if n == 0:
code = '1'
else:
code = 'x'
for x in xrange(1,n):
code += '*(x-%d)' % (x)
return code
return fmacro(x)
The Lisp crowd always brags about their magical macros. I was
wondering if it is possible to emulate some of the functionality in
Python using a function decorator that evals Python code in the stack
frame of the caller. The macro would then return a Python expression
as a string. Granted, I know more Python than Lisp, so it may not work
exactly as you expect.
Any comments and improvements are appreciated.
Regards,
Sturla Molden
__codestore__ = {}
def macro(func):
"""
Lisp-like macros in Python
(C) 2007 Sturla Molden
@macro decorates a function which must return a Python
expression
as a string. The expression will be evaluated in the context
(stack frame)
of the caller.
"""
def macro_decorator(*args,**kwargs):
global __codestore__
import sys
pycode = '(' + func(*args,**kwargs) + ')'
try:
ccode = __codestore__[pycode]
except:
ccode = compile(pycode,'macrostore','eval')
__codestore__[pycode] = ccode
frame = sys._getframe().f_back
try:
retval = eval(ccode,frame.f_globals,frame.f_locals)
return retval
except:
raise
macro_decorator.__doc__ = func.__doc__
return macro_decorator
# Usage example
def factorial(x):
""" computes the factorial function using macro expansion """
@macro
def fmacro(n):
""" returns '1' or 'x*(x-1)*(x-2)*...*(x-(x-1))' """
if n == 0:
code = '1'
else:
code = 'x'
for x in xrange(1,n):
code += '*(x-%d)' % (x)
return code
return fmacro(x)