How can I make @functools.lru_cache
decorator ignore some of the function arguments with regard to caching key?
For example, I have a function that looks like this:
def find_object(db_handle, query):
# (omitted code)
return result
If I apply lru_cache
decorator just like that, db_handle
will be included in the cache key. As a result, if I try to call the function with the same query
, but different db_handle
, it will be executed again, which I'd like to avoid. I want lru_cache
to consider query
argument only.
With cachetools you can write:
from cachetools import cached, hashkey
from random import randint
@cached(cache={}, key=lambda db_handle, query: hashkey(query))
def find_object(db_handle, query):
print("processing {0}".format(query))
return query
queries = list(range(5))
queries.extend(range(5))
for q in queries:
print("result: {0}".format(find_object(randint(0, 1000), q)))
I have at least one very ugly solution. Wrap db_handle
in a object that's always equals, and unwrap it inside the function.
It requires a decorator with quite a bit of helper functions, which makes stack trace quite confusing.
class _Equals(object):
def __init__(self, o):
self.obj = o
def __eq__(self, other):
return True
def __hash__(self):
return 0
def lru_cache_ignoring_first_argument(*args, **kwargs):
lru_decorator = functools.lru_cache(*args, **kwargs)
def decorator(f):
@lru_decorator
def helper(arg1, *args, **kwargs):
arg1 = arg1.obj
return f(arg1, *args, **kwargs)
@functools.wraps(f)
def function(arg1, *args, **kwargs):
arg1 = _Equals(arg1)
return helper(arg1, *args, **kwargs)
return function
return decorator