Python: Dekorateur spezifisches Argument (in keinem Zusammenhang mit eingewickelt Funktion)?
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
?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