def memoize(fn):
    """
    Simple memoization decorator for functions and methods,
    assumes that all arguments to the function can be hashed and
    compared.
    """
    memoized_values = {}

    @wraps(fn)
    def wrapped_fn(*args, **kwargs):
        key = (args, tuple(sorted(kwargs.items())))
        try:
            return memoized_values[key]
        except KeyError:
            memoized_values[key] = fn(*args, **kwargs)
            return memoized_values[key]

    return wrapped_fn
Simple memoization decorator for functions and methods,
    assumes that all arguments to the function can be hashed and
    compared.