2013-02-18 15 views
23

Korzystanie z dekorator LRU cache znaleźć tutaj: http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/Python LRU Cache Dekorator na wystąpienie

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

mogę utworzyć urządzone metody klasy z tym jednak kończy się tworzenie globalnej pamięci podręcznej, które odnoszą się do wszystkich przypadkach klasy testowej. Jednak moim zamiarem było utworzenie pamięci podręcznej dla poszczególnych instancji. Gdybym miał utworzyć instancję 3 testów, miałbym 3 pamięci podręczne LRU zamiast 1 pamięci podręcznej LRU dla wszystkich 3 instancji.

Jedyne wskazanie, że tak się dzieje, to wywołanie metody cache_info() w różnych metodach dekorowanych instancjami klas, wszystkie zwracają te same statystyki pamięci podręcznej (co jest bardzo mało prawdopodobne, ponieważ są one przedmiotem interakcji z bardzo różnymi arguments):

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) 

Czy istnieje dekorator lub trik, który pozwoli mi łatwo spowodować ten dekorator do tworzenia pamięci podręcznej dla każdej instancji klasy?

+1

Pamiętaj, że dekoratorem jest właśnie cukier składniowy dla metody def: pass; method = dekoruj (metoda) '. Więc możesz to przetłumaczyć mechanicznie, aby stworzyć dekorowaną metodę w swoim '__init__'. –

+0

Czy jesteś pewien, że wiesz, do czego służy "metoda klasy"? Ponieważ myślę, że szukasz normalnej metody. Jeśli metoda klasy jest specyficzna dla instancji, jest ona z definicji normalną metodą instancji. Albo dlaczego dokładnie potrzebujesz metody klasowej? A może chcesz mieć pamięć podręczną "na instancję"? – Mayou36

Odpowiedz

28

Zakładając, że nie chcesz modyfikować kodu (np., Ponieważ chcesz mieć możliwość przeniesienia do wersji 3.3 i użyć stdlib functools.lru_cache, lub użyć functools32 z PyPI zamiast kopiowania i wklejania przepisu do kodu), jest jedno oczywiste rozwiązanie: dla każdej instancji utwórz nową metodę wystroju.

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

Awesome. Ale w jaki sposób mogę to zrobić, aby uzyskać tylko uprawnienie @property? – Gilly

2

Jak o tym: a funkcji dekoratora, który owija metoda z lru_cache po raz pierwszy nazywa się na każdej instancji ?

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 

Używaj go tak:

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 

Here's a gist on GitHub z jakiejś dokumentacji inline.