docs: def _get_key(self, fn, args, kwargs):
          """
          Calculate a cache key given a function, args and kwargs.
  
          :param fn: The function
          :type fn: callable or str
  
          :param args: The function args
          :type args: tuple
  
          :param kwargs: The function kwargs
          :type kwargs: dict
  
          :rtype: str
          """
          if args:
              serialized_arguments = (
                  self._store.serialize(args[1:])
                  + self._store.serialize([(k, kwargs[k]) for k in sorted(kwargs.keys())])
              )
          else:
              serialized_arguments = self._store.serialize([(k, kwargs[k]) for k in sorted(kwargs.keys())])
  
          if isinstance(fn, types.MethodType):
              key = self._hash('%s.%s.%s'
                               % (fn.__self__.__class__.__name__,
                                  args[0].__name__,
                                  serialized_arguments))
          elif isinstance(fn, types.FunctionType):
              key = self._hash('%s.%s'
                               % (fn.__name__,
                                  serialized_arguments))
          else:
              key = '%s:' % fn + self._hash(serialized_arguments)
  
          return key