Write a decorator memoize that caches results by both positional and keyword arguments, where f(1, b=2) and f(b=2, a=1) hit the same cache entry only if they bind to the same parameters.
Use inspect.signature(func).bind(*args, **kwargs) and apply_defaults() so that defaults are filled in, then build the key from the bound arguments in parameter order. The wrapper must:
functools.wraps)wrapper.cache (the dict) and wrapper.cache_clear()