Welcome, guest | Sign In | My Account | Store | Cart
import inspect

class Deferred(object):
    def __init__(self, expr):
        self.expr = expr

def revaluatable(func):
    varnames,_,_,defaults = inspect.getargspec(func)
    num_varnames = len(varnames); num_defaults = len(defaults)
    def wrapper(*args, **kwds):
        if len(args) >= num_varnames: # defaults not used here
            return func(*args,**kwds)
        f_locals = dict(zip(varnames,args))
        # maximum number of used defaults
        max_defaults = min(num_defaults, num_varnames-len(args))
        for var,default in zip(varnames[-max_defaults:],defaults[-max_defaults:]):
            if var in kwds: 
                continue    # passed as keyword argument; don't use the default
            if not isinstance(default, Deferred): 
                f_locals[var] = default # non re-evaluatable default
            else:                       # reevaluate default expr. in f_locals
                f_locals[var] = eval(default.expr, func.func_globals, f_locals)
        f_locals.update(kwds)           # add any extra keyword arguments
        return func(**f_locals)
    return wrapper


#======= example ===============================================================    

>>> G = 1   # some global
>>>
>>> @revaluatable
... def f(w, x=Deferred('x**2+G'), y=Deferred('w+x'), z=Deferred('[]'))
...     z.extend([w,x,y]); return z
...
>>> f(3)
[3, 10, 13]
>>> G=3; f(4)
[4, 12, 16]
>>> f(4,5)
[4, 5, 9]
>>> f(-1,1,0)
[-1, 1, 0]
>>> from collections import deque
>>> f(-1, z=deque())
deque([-1, 12, 11])

History

  • revision 2 (17 years ago)
  • previous revisions are not available