Python: Dekorateur spezifisches Argument (in keinem Zusammenhang mit eingewickelt Funktion)?

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

  •  20-08-2019
  •  | 
  •  

Frage

Ich suche einen Caching-Dekorateur zu bauen, die eine Funktion speichert das Ergebnis der Funktion an eine Stelle in der Dekoration angegeben gegeben. So etwas wie folgt aus:

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

Das Argument der Dekorateur ist völlig unabhängig von dem Argument der Funktion Verpackung es ist. Ich habe in ganz wenigen Beispiele aussah, aber ich bin nicht ganz bekommen, wie dies zu tun - ist es möglich, ein Argument für den Dekorateur zu haben, die an unabhängige ist und nicht auf die eingewickelt Funktion übergeben

?
War es hilfreich?

Lösung

Die Idee ist, dass Ihr Dekorateur ist eine Funktion, einen Dekorateur zurück.

FIRST Schreiben Sie Ihren Dekorateur, als ob Sie Ihr Argument wusste eine globale Variable war. Sagen wir mal so etwas wie:

-

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

DANN Schreiben Sie eine Funktion, die CachePath als Arg- und Rückkehr Ihre Dekorateur nimmt.

-

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

Andere Tipps

Ja, es ist. Wie Sie wissen, ist ein Dekorateur eine Funktion. Wenn sie in Form geschrieben:

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

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

das Argument mydecorator geben wird, ist die Funktion foo selbst.

Wenn der Dekorateur ein Argument akzeptiert, wird der Anruf @mydecorator('/path/to') geht tatsächlich die mydecorator Funktion aufzurufen, mit ‚/ path / to‘ zuerst. Dann wird das Ergebnis des Aufrufs zu mydecorator(path) wird aufgerufen, um die Funktion foo zu erhalten. Sie sind effektiv eine dynamische Wrapper-Funktion definiert wird.

Auf den Punkt gebracht, müssen Sie eine weitere Ebene der Dekorateur Funktionen.

Hier ist dies etwas dumme Beispiel:

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

Die Antwort des Paulus ist gut, würde ich das Cache-Objekt bewegen, so dass es nicht jedes Mal gebaut werden muss, und der Cache so auszugestalten, dass es KeyError erhöht, wenn ein Cache-Fehl ist:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top