skpy/util.py
def cacheResult(fn):
        """
        Method decorator: calculate the value on first access, produce the cached value thereafter.

        If the function takes arguments, the cache is a dictionary using all arguments as the key.

        Args:
            fn (method): function to decorate

        Returns:
            method: wrapper function with caching
        """
        cache = {}

        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            # Imperfect key generation (args may be passed as kwargs, so multiple ways to represent one key).
            key = args + tuple(kwargs.items())
            # Order of operations here tries to minimise use of exceptions.
            try:
                # Don't call the function here, as it may throw a TypeError itself (or from incorrect arguments).
                if key in cache:
                    return cache[key]
            except TypeError:
                # Key is not hashable, so we can't cache with these args -- just return the result.
                return fn(*args, **kwargs)
            # Not yet cached, so generate the result and store it.
            cache[key] = fn(*args, **kwargs)
            return cache[key]

        # Make cache accessible externally.
        wrapper.cache = cache
        return wrapper
def cacheResult(fn):
        """
        Method decorator: calculate the value on first access, produce the cached value thereafter.

        If the function takes arguments, the cache is a dictionary using all arguments as the key.

        Args:
            fn (method): function to decorate

        Returns:
            method: wrapper function with caching
        """
        cache = {}

        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            # Imperfect key generation (args may be passed as kwargs, so multiple ways to represent one key).
            key = args + tuple(kwargs.items())
            # Order of operations here tries to minimise use of exceptions.
            try:
                # Don't call the function here, as it may throw a TypeError itself (or from incorrect arguments).
                if key in cache:
                    return cache[key]
            except TypeError:
                # Key is not hashable, so we can't cache with these args -- just return the result.
                return fn(*args, **kwargs)
            # Not yet cached, so generate the result and store it.
            cache[key] = fn(*args, **kwargs)
            return cache[key]

        # Make cache accessible externally.
        wrapper.cache = cache
        return wrapper
Method decorator: calculate the value on first access, produce the cached value thereafter.

        If the function takes arguments, the cache is a dictionary using all arguments as the key.

        Args:
            fn (method): function to decorate

        Returns:
            method: wrapper function with caching