library instruction python caching decorator lru

library - python instruction set



Decorador de caché LRU de Python por instancia (2)

Usando el decorador LRU Cache encontrado aquí: http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/

from lru_cache import lru_cache class Test: @lru_cache(maxsize=16) def cached_method(self, x): return x + 5

Puedo crear un método de clase decorado con esto, pero termina creando una caché global que se aplica a todas las instancias de la clase Test. Sin embargo, mi intención era crear un caché por instancia. Entonces, si tuviera que instanciar 3 pruebas, tendría 3 cachés de LRU en lugar de 1 LRU de memoria caché para las 3 instancias.

La única indicación que tengo de que esto está sucediendo es cuando invoco a cache_info () en los diferentes métodos decorados de instancias de clase, todos devuelven las mismas estadísticas de caché (lo cual es extremadamente improbable porque interactúan con argumentos muy diferentes):

CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128) CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128) CacheInfo(hits=8379, misses=759, maxsize=128, currsize=128)

¿Hay algún decorador o truco que me permita fácilmente hacer que este decorador cree un caché para cada instancia de clase?


¿Qué tal esto: un decorador de funciones que envuelve el método con lru_cache la primera vez que se llama en cada instancia?

def instance_method_lru_cache(*cache_args, **cache_kwargs): def cache_decorator(func): @wraps(func) def cache_factory(self, *args, **kwargs): print(''creating cache'') instance_cache = lru_cache(*cache_args, **cache_kwargs)(func) instance_cache = instance_cache.__get__(self, self.__class__) setattr(self, func.__name__, instance_cache) return instance_cache(*args, **kwargs) return cache_factory return cache_decorator

Úselo así:

class Foo: @instance_method_lru_cache() def times_2(self, bar): return bar * 2 foo1 = Foo() foo2 = Foo() print(foo1.times_2(2)) # creating cache # 4 foo1.times_2(2) # 4 print(foo2.times_2(2)) # creating cache # 4 foo2.times_2(2) # 4

Aquí hay una esencia en GitHub con cierta documentación en línea.


Suponiendo que no desea modificar el código (p. Ej., Porque desea poder realizar el puerto 3.3 y usar stdlib functools.lru_cache , o usar functools32 de PyPI en lugar de copiar y pegar una receta en su código), hay una solución obvia: crear un nuevo método de instancia decorada con cada instancia.

class Test: def cached_method(self, x): return x + 5 def __init__(self): self.cached_method = lru_cache(maxsize=16)(self.cached_method)