2009-03-19 9 views
6

Szukam, aby zbudować dekorator buforowania, który, biorąc pod uwagę funkcję, buforuje wynik funkcji do lokalizacji określonej w dekoracji. Coś takiego:Python: specyficzny argument dekoratora (niezwiązany z funkcją owijania)?

@cacheable('/path/to/cache/file') 
def my_function(a, b, c): 
    return 'something' 

Argument do dekoratora jest całkowicie niezależny od argumentu funkcji, którą zawija. Spojrzałem na kilka przykładów, ale nie wiem, jak to zrobić - czy jest możliwe argumentowanie dekoratora, który nie ma związku z funkcją owijania i nie jest nią przekazywany?

Odpowiedz

9

Chodzi o to, że Twój dekorator jest funkcją zwracającą dekoratora.

PIERWSZA Napisz swojego dekoratora, jakbyś wiedział, że twój argument jest zmienną globalną. Powiedzmy, że coś takiego:

-

def decorator(f): 
    def decorated(*args,**kwargs): 
     cache = Cache(cachepath) 
     if cache.iscached(*args,**kwargs): 
      ... 
     else: 
      res = f(*args,**kwargs) 
      cache.store((*args,**kwargs), res) 
      return res 
    return decorated 

WTEDY Napisz funkcję, która pobiera cachepath jako arg i zwróci dekorator.

-

def cache(filepath) 
    def decorator(f): 
     def decorated(*args,**kwargs): 
      cache = Cache(cachepath) 
      if cache.iscached(*args,**kwargs): 
       ... 
      else: 
       res = f(*args,**kwargs) 
       cache.store((*args,**kwargs), res) 
       return res 
     return decorated 
    return decorator 
5

Tak jest. Jak wiesz, dekorator jest funkcją. Kiedy zapisać w postaci:

def mydecorator(func): 
    def wrapper(*args, **kwargs): 
     return func(*args, **kwargs) 
    return wrapper 

@mydecorator 
def foo(a, b, c): 
    pass 

argument przekazany do mydecorator jest funkcja foo sama.

Gdy dekorator akceptuje argument, wywołanie @mydecorator('/path/to') wywołuje funkcję mydecorator najpierw "/ path/to". Następnie wywołanie funkcji mydecorator(path) zostanie wywołane, aby otrzymać funkcję foo. Skutecznie definiujesz funkcję dynamicznego opakowania.

W skrócie, potrzebujesz kolejnej warstwy funkcji dekoratora.

Oto to nieco głupie przykład:

def addint(val): 
    def decorator(func): 
     def wrapped(*args, **kwargs): 
      result = func(*args, **kwargs) 
      return result + val 
     return wrapped # returns the decorated function "add_together" 
    return decorator # returns the definition of the decorator "addint" 
         # specifically built to return an extra 5 to the sum 

@addint(5) 
def add_together(a, b): 
    return a + b 

print add_together(1, 2) 
# prints 8, not 3 
3

odpowiedź Pawła jest dobry, chciałbym przenieść obiekt cache, więc nie muszą być budowane za każdym razem i zaprojektować swoją pamięć tak, że podnosi KeyError gdy brakuje pamięci podręcznej:

def cache(filepath): 
    def decorator(f): 
     f._cache = Cache(cachepath) 
     def decorated(*args,**kwargs): 
      try: 
       key = (args, kwargs) 
       res = f._cache.get(key) 
      except KeyError: 
       res = f(*args, **kwargs) 
       f._cache.put(key, res) 
      return res 
     return decorated 
    return decorator 
Powiązane problemy