WGH
como puedo hacer @functools.lru_cache
¿El decorador ignora algunos de los argumentos de la función con respecto a la clave de almacenamiento en caché?
Por ejemplo, tengo una función que se ve así:
def find_object(db_handle, query):
# (omitted code)
return result
si aplico lru_cache
decorador así, db_handle
se incluirán en la clave de caché. Como resultado, si intento llamar a la función con el mismo query
pero diferente db_handle
, se ejecutará nuevamente, lo que me gustaría evitar. Quiero lru_cache
considerar query
argumento solamente.
yan
Con cachetools puedes escribir:
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)))
Deberá instalar cachetools (pip install cachetools
).
La sintaxis es:
@cached(
cache={},
key=lambda <all-function-args>: hashkey(<relevant-args>)
)
Aquí hay otro ejemplo que incluye argumentos de palabras clave:
@cached(
cache={},
key=lambda a, b, c=1, d=2: hashkey(a, c)
)
def my_func(a, b, c=1, d=2):
return a + c
En el ejemplo anterior, tenga en cuenta que los argumentos de entrada de la función lambda coinciden con el my_func
argumentos No es necesario que coincida exactamente con argspec si no es necesario. Por ejemplo, puede usar kwargs para eliminar cosas que no son necesarias en el hashkey:
@cached(
cache={},
key=lambda a, b, c=1, **kwargs: hashkey(a, c)
)
def my_func(a, b, c=1, d=2, e=3, f=4):
return a + c
En el ejemplo anterior no nos importa d=
, e=
y f=
args al buscar un valor de caché, por lo que podemos aplastarlos con **kwargs.
-
¿Puede dar más detalles sobre esta respuesta con qué clave y hashkey son?
– tommy
19 de noviembre de 2021 a las 1:32
-
Para cualquier otra persona que desee una respuesta al comentario de @Tommy, pude encontrar la descripción de
key
yhashkey
en esta sección de lacachetools
documentos. Esencialmente,key
es una función que devuelve una clave de caché, yhashkey()
devuelve una tupla de sus argumentos como una clave de caché interna y verifica que cada argumento se pueda modificar.– Homero Simpson
16 de febrero de 2022 a las 22:11
-
¿Qué imprime esto? Imprime:
processing 0\n result: 0\n processing 1\n result: 1\n processing 2\n result: 2\n processing 3\n result: 3\n processing 4\n result: 4\n result: 0\n result: 1\n result: 2\n result: 3\n result: 4\n
???– joseville
24 de febrero de 2022 a las 18:11
-
@Tommy, edité la respuesta para incluir más explicaciones sobre la sintaxis necesaria. Espero que esto ayude.
– JGC
24 de marzo de 2022 a las 16:44
-
en general para la función
def function(a,b):
donde solo se utilizará b como clave de caché, haga@cached(cache={}, key=lambda a,b: hashkey(b))
(la sintaxis es confusa a primera vista)– stam
10 de febrero a las 17:58
Tengo al menos una solución muy fea. Envoltura db_handle
en un objeto que siempre es igual, y desenvuélvelo dentro de la función.
Requiere un decorador con bastantes funciones de ayuda, lo que hace que el seguimiento de la pila sea bastante confuso.
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
-
Estoy reviviendo esta respuesta muy antigua, pero ¿cómo usarías el
lru_cache_ignoring_first_argument
¿decorador?– Sanandrea
20 dic 2022 a las 17:00