Inline factory usage

Inline factory usage#

Consider the function cache_factory you built just now:

def cache_factory(maxsize):
    def cache(f):
        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

    return cache

You can also apply it directly with the at sign @ syntax, without having to create intermediate cache decorators:

@cache_factory(1000)
def fn1(*args):
    ...

@cache_factory(2000)
def fn2(*args):
    ...

This works because the at sign @ expects a decorator, and the expression decorator_factory(...) returns a decorator, so you can use it directly in front of the at sign @. If you remember that the at sign @ is just syntactic sugar, you can unroll the operation that is happening.

So,

@cache_factory(1000)
def fn1(*args):
    ...

is the same as

def fn1(*args):
    ...

fn1 = cache_factory(1000)(fn1)

The line cache_factory(1000)(fn1) might look odd, but function application evaluates from left to right, so cache_factory(1000) first evaluates to a cache decorator with a maximum size of 1,000 items. Suppose it is called cache1000. So, cache_factory(1000)(fn1) evaluates to cache1000(fn1), which is the regular decorator application you are used to.