Mit Dekoratoren lassen sich einfache Änderungen an aufrufbaren Objekten wie Funktionen, Methoden oder Klassen vornehmen. Wir werden uns in diesem Tutorial mit Funktionen beschäftigen. Die Syntax:
@decorator
def funktionen(arg):
return "wert"
Ist äquivalent zu:
def funktion(arg):
return "value"
funktion = decorator(funktion) # dies übergibt die Funktion an den Dekorator und weist sie wieder den Funktionen zu
Ein Dekorator ist nur eine weitere Funktion, die eine Funktion annimmt und eine zurückgibt, also:
def repeater(alte_funktion):
def neue_funktion(*args, **kwds):
# führt die alte Funktion aus
alte_funktion(*args, **kwds)
# macht es zweimal
alte_funktion(*args, **kwds)
# gibt die neue_funktion zurück, sonst würde sie den Wert nicht neu zuweisen
return neue_funktion
Beispiel:
def multiplizieren(multiplikator):
def multiplikator_generator(alte_funktion):
def neue_funktion(*args, **kwds):
return multiplikator * alte_funktion(*args, **kwds)
return neue_funktion
return multiply_generator # liefert den neuen Generator
# Verwendung
@multiplizieren(3) # multiplizieren ist kein Generator, aber multiplizieren(3)
def rückgabe_zahl(zahl):
return zahl
# Jetzt wird return_num dekoriert und an sich selbst neu zugewiesen
rückgabe_zahl(5) # sollte 15 zurückgeben
Übung
Erstelle eine Dekorator-Fabrik, die einen Dekorator zurückgibt, der Funktionen mit einem Argument dekoriert. Die Fabrik soll ein Argument, einen Typ, entgegennehmen und dann einen Dekorator zurückgeben, der die Funktion prüfen soll, ob die Eingabe der richtige Typ ist. Wenn sie falsch ist, sollte sie print("Schlechter Typ") ausgeben (in Wirklichkeit sollte sie einen Fehler auslösen, aber das Auslösen von Fehlern ist nicht Bestandteil dieses Tutorials). Schaue dir den Code des Tutorials und die erwartete Ausgabe an, um zu sehen, was es ist, wenn du verwirrt bist (ich weiß, ich wäre es.) Die Verwendung von isinstance(object, type_of_object) oder type(object) könnte helfen.
def type_check(richtiger_Typ):
# Code hier einfügen
@type_check(int)
def mal2(zahl):
return zahl*2
print(mal2(2))
mal2('Keine Zahl')
@type_check(str)
def erster_Buchstabe(wort):
return wort[0]
print(erster_Buchstabe('Hello World'))
erster_Buchstabe(['Kein', String'])
def type_check(richtiger_Typ):
def check(alte_funktion):
def neue_funktion(arg):
if (isinstance(arg, richtiger_Typ)):
return alte_funktion(arg)
else:
print("Schlechter Typ")
return neue_funktion
return check
@type_check(int)
def mal2(num):
return num*2
print(mal2(2))
mal2('Keine Zahl')
@type_check(str)
def erster_Buchstabe(wort):
return wort[0]
print(erster_Buchstabe('Hello World'))
erster_Buchstabe(['Kein', 'String'])
test_output_contains("4")
test_output_contains("Schlechter Typ")
test_output_contains("H")
test_output_contains("Schlechter Typ")
success_msg("Hervorragend!")