old_contents: """
  - the popular ``memoize_default`` works like a typical memoize and returns the
    default otherwise.
  - ``CachedMetaClass`` uses ``memoize_default`` to do the same with classes.
  """
  
  
  def memoize_default(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):
              if evaluator_is_first_arg:
                  cache = obj.memoize_cache
              elif second_arg_is_evaluator:  # needed for meta classes
                  cache = args[0].memoize_cache
              else:
                  cache = obj._evaluator.memoize_cache
  
              try:
                  memo = cache[function]
              except KeyError:
                  memo = {}
                  cache[function] = memo
  
              key = (args, frozenset(kwargs.items()))
              if key in memo:
                  return memo[key]
              else:
                  memo[key] = default
                  rv = function(obj, *args, **kwargs)
                  memo[key] = rv
                  return rv
          return wrapper
      return func
  
  
  class CachedMetaClass(type):
      """
      This is basically almost the same than the decorator above, it just caches
      class initializations. I haven't found any other way, so I'm doing it with
      meta classes.
      """
      @memoize_default(None, second_arg_is_evaluator=True)
      def __call__(self, *args, **kwargs):
          return super(CachedMetaClass, self).__call__(*args, **kwargs)
  
new_contents: """
  - the popular ``memoize_default`` works like a typical memoize and returns the
    default otherwise.
  - ``CachedMetaClass`` uses ``memoize_default`` to do the same with classes.
  """
  
  
  def memoize_default(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):
              if evaluator_is_first_arg:
                  cache = obj.memoize_cache
              elif second_arg_is_evaluator:  # needed for meta classes
                  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:
                  memo[key] = default
                  rv = function(obj, *args, **kwargs)
                  memo[key] = rv
                  return rv
          return wrapper
      return func
  
  
  class CachedMetaClass(type):
      """
      This is basically almost the same than the decorator above, it just caches
      class initializations. I haven't found any other way, so I'm doing it with
      meta classes.
      """
      @memoize_default(None, second_arg_is_evaluator=True)
      def __call__(self, *args, **kwargs):
          return super(CachedMetaClass, self).__call__(*args, **kwargs)
  
subject: fix cache memoization