def memoize(obj):
  cache = obj.cache = {}

  @functools.wraps(obj)
  def memoizer(*args, **kwargs):
    key = tuple(list(args) + sorted(kwargs.items()))
    if key not in cache:
      cache[key] = obj(*args, **kwargs)
    return cache[key]
  return memoizer