Search code examples
pythoncachingfunctools

Why does my LRU cache miss with the same argument?


I have some code that looks like this:

from functools import lru_cache


@lru_cache()
def get_cheese(type):
    print('{}? We\'re all out.'.format(type))
    return None

get_cheese(type='cheddar')
get_cheese('cheddar')
print(get_cheese.cache_info())

cache_info() reports that there were two misses - yet I called the function with the same argument.

It actually took some doing, but I figured out that it's because in one instance I was using the keyword arg, and the other I was using a positional argument.

But why?


Solution

  • The wrapper created by functools.lru_cache makes no attempt to inspect or copy the signature of the wrapped function. The Python version is defined as

    def wrapper(*args, **kwargs):
        ...
        key = make_key(args, kwds, typed)
        ...
    

    and as you can see, it builds the key used in the cache based on args and kwargs, without knowing whether any positional or keyword arguments are equivalent. The C version similarly builds the key without caring about the original signature.

    As for why it's designed that way? I'm not aware of the original rationale. It could have been deliberate, either for simplicity of implementation or to avoid the overhead of matching keyword arguments to positionals, or it could have been an oversight. If you think changing it would be worthwhile, you could bring it up on the issue tracker.