* kapselt eine vorhandene Funktion in einer anderen Funktion
* dabei übernimmt die kapselnde Funktion den Namen der gekapselten Funktion
===== Parametrisierter Dekorator =====
* beim Aufrufen von Dekoratoren wird in der folgenden Reihenfolge aufgerufen
* Funktion1 (ich nenne sie Factory) bekommt die Dekorator-Parameter übergeben
* Funktion2 (ich nenne sie Dekorator-Funktion) bekommt die aufzurufende Funktion übergeben
* Funktion3 (ich nenne sie Wraper) bekommt die Parameter für die gekapselte Funktion übergeben
def decofactory(decorator_param):
def decoratorfunction(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
return decoratorfunction
@decoratorfactory(someparameter)
def actual_function(param1, param2):
pass
* Technisch ist der Aufruf decofactory(decorator_param)(func) -> das gibt dann Wrapper zurück was dann wiederum aufgerufen wird
* decofactory nimmt die Parameter des Dekorators auf
* decoratorfunction bekommt die Methode übergeben
==== Default values in Parametern von Dekoratoren ====
def decofactory(decorator_param=1):
def decoratorfunction(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
return decoratorfunction
@decoratorfactory
def actual_function(param1, param2):
pass
* würde man actual_function aufrufen würde man einen Verweis auf eine Funktion zurückerhalten und die eigentliche Funktion nicht ausgeführt werden
* der Dekorator wird ohne Parameter aufgerufen (und ohne leere Klammern -> aka. kein Funktionsaufruf ohne Parameter)
* es wird nicht decoratorfactory(Dekorator-Parameter)(func) aufgerufen
* sondern decoratorfactory(func)
* dadurch wird decoratorfunction die Funktion übergeben und nicht an decoratorfunction
* dadurch wiederum kommt der Default-Value in decoratorfunction nicht zum tragen (da ja ein Wert übergeben wurde
=== Lösung 1 ===
Statt:
@decoratorfactory
def actual_function(param1, param2):
pass
@decoratorfactory()
def actual_function(param1, param2):
pass
* Hinter dem Dekorator steht (), es ist jetzt also ein leerer Funktionsaufruf und letztendlich wird decoratorfactory()(func) aufgerufen.
* Setzt allerdings voraus die Nutzer des Dekorators das wissen und konsequent beachten
* die IDE oder Python wird das weglassen von () nicht als Fehler melden
=== Lösung 2 ===
def decofactory(decorator_param=1):
def decoratorfunction(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
if callable(decorator_param):
# Set the default-value
decorator_param = 1
return decoratorfunction(decorator_param)
return decoratorfunction
* neu ist "if callable"
* prüft ob decorator_param eine Funktion übergeben bekommen hat
* das wäre der Fall wenn der Dekorator ohne "()" aufgerufen worden wäre, dann würde gleich die zu dekorierende Funktion übergeben werden
* in diesem Fall wird decoratorfunction mit dem Inhalt von decorator_param (der zu dekorierenden Funktion) aufgerufen -> das heißt es wird wrapper zurückgegeben, das ist das was erwartet wird (das der unmittelbare Wrapper zurückkommt)
* **Achtung:** decorator_param (der erste Parameter der ersten Funktion) darf natürlich kein callable erwarten - sprich keine Funktion oder Klasse, sonst funktioniert dieser Weg nicht