otra metodos metodo llamar importar clases clase python caching python-decorators lru functools

metodos - importar clases en python



Functools de Python lru_cache con métodos de clase: liberar objeto (1)

¿Cómo puedo usar functools ''lru_cache dentro de las clases sin pérdida de memoria? En el siguiente ejemplo mínimo, la instancia de foo no se lanzará aunque se salga del alcance y no tenga referencia (excepto la caché lru).

from functools import lru_cache class BigClass: pass class Foo: def __init__(self): self.big = BigClass() @lru_cache(maxsize=16) def cached_method(self, x): return x + 5 def fun(): foo = Foo() print(foo.cached_method(10)) print(foo.cached_method(10)) # use cache return ''something'' fun()

Pero foo y por foo.big tanto foo.big (una gran BigClass ) siguen vivos

import gc; gc.collect() # collect garbage len([obj for obj in gc.get_objects() if isinstance(obj, Foo)]) # is 1

Eso significa que las instancias de Foo / BigClass aún residen en la memoria. Incluso la eliminación de Foo (del Foo ) no los liberará.

¿Por qué lru_cache se aferra a la instancia? ¿El caché no usa el hash y no el objeto real?

¿Cuál es la forma recomendada de usar lru_caches dentro de las clases?

Sé de dos soluciones: utilizar cachés por instancia o hacer que la memoria caché ignore el objeto (lo que podría dar lugar a resultados erróneos)


Esta no es la solución más limpia, pero es completamente transparente para el programador:

import functools import weakref def memoized_method(*lru_args, **lru_kwargs): def decorator(func): @functools.wraps(func) def wrapped_func(self, *args, **kwargs): # We''re storing the wrapped method inside the instance. If we had # a strong reference to self the instance would never die. self_weak = weakref.ref(self) @functools.wraps(func) @functools.lru_cache(*lru_args, **lru_kwargs) def cached_method(*args, **kwargs): return func(self_weak(), *args, **kwargs) setattr(self, func.__name__, cached_method) return cached_method(*args, **kwargs) return wrapped_func return decorator

Toma exactamente los mismos parámetros que lru_cache , y funciona exactamente igual. Sin embargo, nunca pasa self a lru_cache y en su lugar utiliza un lru_cache por instancia.