code: def _memoize_default(
      default=_NO_DEFAULT,
      evaluator_is_first_arg=False,
      second_arg_is_evaluator=False,
  ):
      """This is a typical memoization decorator, BUT there is one difference:
      To prevent recursion it sets defaults.
  
      Preventing recursion is in this case the much bigger use than speed. I
      don't think, that there is a big speed difference, but there are many cases
      where recursion could happen (think about a = b; b = a).
      """
  
      def func(function):
          def wrapper(obj, *args, **kwargs):
              # TODO These checks are kind of ugly and slow.
              if evaluator_is_first_arg:
                  cache = obj.memoize_cache
              elif second_arg_is_evaluator:
                  cache = args[
                      0
                  ].memoize_cache  # needed for meta classes
              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)
                  memo[key] = rv
                  return rv
  
          return wrapper
  
      return func
  
label_desc: Use image node_id 1 for calling a global function with example usage: _memoize_default(default, evaluator_is_first_arg, second_arg_is_evaluator) and returns: func, wrapper, memo, rv