class_docstr: Decorator for LRU-cached function
  
  timeout parameter specifies after how many seconds a cached entry should
  be considered invalid.
class_docstr_tok: ["Decorator","for","LRU-cached","function","timeout","parameter","specifies","after","how","many","seconds","a","cached","entry","should","be","considered","invalid","."]
code: def __call__(self, func):
      cache = self.cache
      marker = _MARKER
  
      def cached_wrapper(*args, **kwargs):
          def list_to_tuple(list_of_lists):
              return tuple(
                  tuple(x) if isinstance(x, list) else x
                  for x in list_of_lists
              )
  
          def get_default_args(remove_self, func, rargs, kwargs):
              """
              returns a dictionary of arg_name:default_values for the input function
              """
              if hasattr(inspect, "getfullargspec"):
                  argspec = inspect.getfullargspec(func)
                  args = argspec.args
                  defaults = argspec.defaults
              else:
                  args, _, _, defaults = inspect.getargspec(func)
              args = args or []
              defaults = defaults or []
              if remove_self:
                  args = args[1:]
  
              if defaults is not None:
                  ddict = dict(zip(args[-len(defaults) :], defaults))
                  new_kwargs = dict(
                      zip(
                          args[-len(defaults) :],
                          rargs[len(args) - len(defaults) :],
                      )
                  )
                  ddict.update(new_kwargs)
                  ddict.update(kwargs)
              else:
                  ddict = dict()
              new_rargs = rargs[: len(args) - len(defaults)]
              return new_rargs, ddict
  
          try:
              args, kwargs = get_default_args(
                  self.remove_self, self.real_func or func, args, kwargs
              )
              args_t = tuple(
                  list_to_tuple(arg) if isinstance(arg, list) else arg
                  for arg in args
              )
              kwargs_t = frozenset(
                  (
                      (kwarg[0], list_to_tuple(kwarg[1]))
                      if isinstance(kwarg[1], list)
                      else kwarg
                      for kwarg in kwargs.items()
                  )
              )
              key = (args_t, kwargs_t) if kwargs else args_t
              val = cache.get(key, marker)
          except TypeError as e:
              if self._ignore_unhashable_args:
                  return func(*args, **kwargs)
              else:
                  raise e
          else:
              if val is marker:
                  val = func(*args, **kwargs)
                  cache.put(key, val)
              return val
  
      def _maybe_copy(source, target, attr):
          value = getattr(source, attr, source)
          if value is not source:
              setattr(target, attr, value)
  
      _maybe_copy(func, cached_wrapper, "__module__")
      _maybe_copy(func, cached_wrapper, "__name__")
      _maybe_copy(func, cached_wrapper, "__doc__")
      cached_wrapper._cache = cache
      return cached_wrapper
  
imports: from abc import abstractmethod
  from abc import ABCMeta
  import threading
  import time
  import uuid
  import inspect
label_desc: Use image node_id 2 for calling the lru_cache obj's underlying member method code with example usage: obj.__call__(func) and returns: cached_wrapper, tuple, new_rargs,  ddict, val, func