def memoize_default(default=NO_DEFAULT, evaluator_is_first_arg=False, second_arg_is_evaluator=False):
 def func(function):
  def wrapper(obj, *args, **kwargs):
   if evaluator_is_first_arg:
    cache = obj.memoize_cache
   elif second_arg_is_evaluator:
    cache = args[0].memoize_cache
   else:
    cache = obj._evaluator.memoize_cache
   try:
    memo = cache[function]
   except KeyError:
    memo = {}
    cache[function] = memo
   key = (obj, args, frozenset(kwargs.items()))
   if (key in memo):
    return memo[key]
   else:
    if (default is not NO_DEFAULT):
     memo[key] = default
    rv = function(obj, *args, **kwargs)
    if inspect.isgenerator(rv):
     rv = list(rv)
    memo[key] = rv
    return rv
  return wrapper
 return func

def memoize_default ( default = NO_DEFAULT , evaluator_is_first_arg = False , second_arg_is_evaluator = False ) : def func ( function ) : def wrapper ( obj , * args , ** kwargs ) : if evaluator_is_first_arg : cache = obj . memoize_cache elif second_arg_is_evaluator : cache = args [ 0 ] . memoize_cache else : cache = obj . _evaluator . memoize_cache try : memo = cache [ function ] except KeyError : memo = { } cache [ function ] = memo key = ( obj , args , frozenset ( kwargs . items ( ) ) ) if ( key in memo ) : return memo [ key ] else : if ( default is not NO_DEFAULT ) : memo [ key ] = default rv = function ( obj , * args , ** kwargs ) if inspect . isgenerator ( rv ) : rv = list ( rv ) memo [ key ] = rv return rv return wrapper return func
this is a typical memoization decorator .