code: def memoize(func: Callable) -> Callable:
      """
      memoize(func) -> Callable
  
      Decorates a function for memoization, which explicitly caches the function's
      output.
  
      :param Callable func: The function to memoize
      """
  
      @functools.wraps(func)
      def cache_nodes(
          self: Protocol, *args: Any, **kwargs: Any
      ) -> AbstractTensor:
          if get_config().debug:
              return func(self, *args, **kwargs)
  
          hashable_args = make_hashable(args)
          hashable_kwargs = make_hashable(kwargs)
          node_key = (func.__name__, hashable_args, hashable_kwargs)
  
          cached_result = nodes.get(node_key, None)
          if cached_result is not None:
              return cached_result
  
          result = func(self, *args, **kwargs)
  
          nodes[node_key] = result
          return result
  
      return cache_nodes
  
imports: import functools
  from abc import ABC
  from types import TracebackType
  from typing import Any
  from typing import Callable
  from typing import Optional
  import tensorflow
  import tf_encrypted
  from ..config import get_config
  from ..tensor.factory import AbstractTensor
label_desc: Use image node_id 2 for calling a global function with example usage: memoize(func) and returns: cache_nodes, result, func, cached_result