Python: argomento specifico del decoratore (non correlato alla funzione wrapping)?

StackOverflow https://stackoverflow.com/questions/660727

  •  20-08-2019
  •  | 
  •  

Domanda

Sto cercando di creare un decoratore di memorizzazione nella cache che, data una funzione, memorizza nella cache il risultato della funzione in una posizione specificata nella decorazione. Qualcosa del genere:

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

L'argomento per il decoratore è completamente separato dall'argomento per la funzione che sta avvolgendo. Ho esaminato alcuni esempi, ma non riesco proprio a capire come farlo - è possibile avere un argomento per il decoratore che non è correlato e non è passato alla funzione wrapped?

È stato utile?

Soluzione

L'idea è che il tuo decoratore sia una funzione che restituisce un decoratore.

PRIMO Scrivi il tuo decoratore come se sapessi che il tuo argomento era una variabile globale. Diciamo qualcosa del tipo:

-

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

POI Scrivi una funzione che prende cachepath come arg e restituisce il tuo decoratore.

-

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

Altri suggerimenti

Sì, lo è. Come sai, un decoratore è una funzione. Se scritto nel modulo:

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

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

l'argomento passato a mydecorator è la funzione foo stessa.

Quando il decoratore accetta un argomento, la chiamata @mydecorator('/path/to') in realtà chiamerà prima la funzione mydecorator con '/ path / to'. Quindi il risultato della chiamata a mydecorator(path) verrà chiamato per ricevere la funzione <=>. Stai effettivamente definendo una funzione di wrapper dinamico.

In poche parole, hai bisogno di un altro livello di funzioni di decorazione.

Ecco questo esempio un po 'sciocco:

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

La risposta di Paul è buona, sposterei l'oggetto cache in modo che non debba essere creato ogni volta, e progetterei la tua cache in modo che aumenti KeyError in caso di mancanza della cache:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top