2015-06-09 5 views
13

Как я могу сделать @functools.lru_cache decorator игнорировать некоторые аргументы функции в отношении ключа кеширования?Сделать @lru_cache игнорировать некоторые аргументы функции

Например, у меня есть функция, которая выглядит следующим образом:

def find_object(db_handle, query): 
    # (omitted code) 
    return result 

Если я применяю lru_cache декоратор просто так, db_handle будет включен в кеше. В результате, если я попытаюсь вызвать функцию с тем же query, но другой db_handle, он будет выполнен снова, чего я бы хотел избежать. Я хочу, чтобы lru_cache рассмотрел только аргумент query.

ответ

8

С cachetools вы можете написать:

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))) 
1

У меня есть хотя бы одно очень уродливое решение. Оберните 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