Сделать @lru_cache игнорировать некоторые аргументы функции
Как я могу сделать @functools.lru_cache
decorator игнорировать некоторые аргументы функции в отношении ключа кеширования?
Например, у меня есть функция, которая выглядит так:
def find_object(db_handle, query):
# (omitted code)
return result
Если я применил декор lru_cache
точно так же, db_handle
будет включен в ключ кеша. В результате, если я попытаюсь вызвать функцию с тем же query
, но с другим db_handle
, он будет выполнен снова, чего я бы хотел избежать. Я хочу, чтобы lru_cache
рассматривал только аргумент query
.
Ответы
Ответ 1
С помощью cachetools вы можете написать:
from cachetools import cached
from cachetools.keys import 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)))
Ответ 2
У меня есть хотя бы одно очень уродливое решение. Оберните db_handle
в объект, который всегда равен, и разверните его внутри функции.
Для этого требуется декоратор с довольно небольшими вспомогательными функциями, что делает трассировку стека довольно запутанной.
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