Decorator with two arguments#
Now that the maximum size is isolated as a variable, it becomes clear that the maximum size is a good candidate to become an argument to the caching decorator; something like
def cache(f, maxsize):
cache = {}
def cached_f(*args):
if args not in cache:
if len(cache) >= MAXSIZE:
cache.popitem()
cache[args] = f(*args)
return cache[args]
return cached_f
By writing the decorator like this, the maximum size can now be customised per application of the decorator instead of being a global that is shared across all applications…
But how do you apply the decorator cache seen above?
If fn is the function to decorate, you can apply the decorator like this:
fn = cache(fn, 1000)
This adds a cache to the function fn with a maximum size of 1,000 items.
If, later on, you have a second function fn2 to add a cache to, you could decorate it with
fn2 = cache(fn2, 2000)
This adds a cache to fn2 with a maximum size of 2,000 that is independent of the cache of fn!
This is progress, already.
But the decorator cache with two arguments has a problem…
The decorator cache with two arguments can’t be applied with the at sign @ syntax.
Think about it…
How would you do it?
And swapping the order of the arguments doesn’t work, either…
To use the at sign @ syntax, you’d want to do something like this:
cache(1000)
def fn(*args):
...
But for this to be possible, cache(1000) must be a decorator, which can only happen if:
cacheexpects a single argument, the cache size; andcache(maxsize)returns a decorator.
So, that is what you have to do!
You have to write cache as a factory of decorators.
cache must be a function that returns decorators!