Search code examples
pythonpython-3.xcaching

How to ignore function arguments with cachetools ttl_cache


I'm exploiting the cachetools @ttl_cache decorator (not @cached). I need to ignore some params in the cache key. E.g,.

@ttl_cache(maxsize=1024, ttl=600)
def my_func(foo, ignore_bar, ignore_baz):
    # do stuff

Working that way, I get this:

>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache miss
>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache hit
>>> my_func("foo", "ignore_bar_bar", "ignore_baz_baz") # cache miss!

What I need:

>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache miss
>>> my_func("foo", "ignore_bar", "ignore_baz")         # cache hit
>>> my_func("foo", "ignore_bar_bar", "ignore_baz_baz") # cache hit!!!!!

Is there a way to get that using @ttl_cache?


Solution

  • I haven't used cachetools, but I've looked at the docs out of interest. Apparently, there's no built-in way. If you really need this functionality, I can suggest a hack like the following:

    class PackedArgs(tuple):
        def __hash__(self):
            return hash(self[0])
    
        def __eq__(self, other):
            if isinstance(other, self.__class__):
                return self[0] == other[0]
            else:
                return NotImplemented
    
    def pack_args(func):
        def inner(packed_args):
            return func(*packed_args)
        return inner
    
    def unpack_args(func):
        def inner(*args):
            return func(PackedArgs(args))
        return inner
    
    @unpack_args
    @ttl_cache(maxsize=1024, ttl=600)
    @pack_args
    def my_func(foo, ignore_bar, ignore_baz):
        # do stuff
    

    Essentially: "pack" your function's arguments to a single tuple-like object that hashes as it's 0th element and causes @ttl_cache to behave like you need. Then, "unpack" them to restore the normal interface and avoid actually having to pass this one big argument when calling.

    Please note that this is just a (very hacky) concept, I haven't tested this code at all. It probably won't work as is.

    By the way, your requirement sounds interesting. You can submit it to cachetools as a feauture request and link this thread. I can imagine it being implemented as something like a key= kwarg lambda, similar to builtin sort's.