code: def memoize(f):
      
      # TODO: Recommend that f's arguments be immutable
      memory = {}
  
      @wraps(f)
      def new_f(*args):
          try:
              return memory[args]
          except KeyError:
              r = f(*args)
              memory[args] = r
              return r
  
      return new_f
docs: A decorator that memoizes a function result based on its parameters. For example, this can be
      used in place of lazy initialization. If the decorating function is invoked by multiple
      threads, the decorated function may be called more than once with the same arguments.