Python3.2와
이상, 당신은 functools.lru_cache
를 사용할 수 있습니다. total
을 functools.lru_cache
으로 직접 꾸밀 경우 lru_cache
은 self
및 x
두 값의 값을 기반으로 total
의 반환 값을 캐시합니다. lru_cache의 내부 dict는 self에 대한 참조를 저장하기 때문에 @lru_cache를 클래스 메소드에 직접 적용하면 self
에 대한 순환 참조가 생성되어 클래스의 인스턴스를 참조 해제 할 수 없게 (따라서 메모리 누수) 만듭니다.
import functools
import weakref
def memoized_method(*lru_args, **lru_kwargs):
"""
https://stackoverflow.com/a/33672499/190597 (orly)
"""
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
class MyObject(object):
def __init__(self, a, b):
self.a, self.b = a, b
@memoized_method()
def total(self, x):
print('Calling total (x={})'.format(x))
return (self.a + self.b) * x
def subtotal(self, y, z):
return self.total(x=y) + z
mobj = MyObject(1,2)
mobj.subtotal(10, 20)
mobj.subtotal(10, 30)
인쇄 : 그것은 첫 번째, self
이외의 모든 인수에 따라 결과를 캐시하고, 순환 참조 문제를 방지하기 위해 weakref를 사용합니다 - 당신은 클래스 메소드와 lru_cache
을 사용할 수 있습니다
Here is a workaround
Calling total (x=10)
한 번만.
또는이 당신이 딕셔너리를 사용하여 자신의 캐시를 롤 수있는 방법입니다 :이 딕셔너리 기반 캐시를 통해 lru_cache
의
class MyObject(object):
def __init__(self, a, b):
self.a, self.b = a, b
self._total = dict()
def total(self, x):
print('Calling total (x={})'.format(x))
self._total[x] = t = (self.a + self.b) * x
return t
def subtotal(self, y, z):
t = self._total[y] if y in self._total else self.total(y)
return t + z
mobj = MyObject(1,2)
mobj.subtotal(10, 20)
mobj.subtotal(10, 30)
장점 중 하나는 lru_cache
스레드 안전 것입니다.lru_cache
에는 장기 실행 프로세스가 total
을 여러 번 호출하여 다른 값이 x
인 여러 번 발생하기 때문에 은 바운드없이 메모리 사용을 방지하는 데 도움이되는 maxsize
매개 변수가 있습니다.
시도해 보셨습니까? http://stackoverflow.com/a/18723434/2570677 나는 내 코드에서 그것을 사용하고 완벽하게 작동합니다. –
'@ functools.lru_cache'라고 가정하고 계신가요? –
에서 링크 된 리소스를 통해 기본 캐시 기능으로'total'을 꾸미는 것을 막을 수 있습니까? '@ functools.lru_cache (maxsize = N)'을 넣으면 같은 인수에 대해'N' 결과가 캐시됩니다. 왜 당신 시나리오에서 그렇게되지 않을까요? –