Python-Dekorateure
Python-Dekoratoren
Ein Dekorateur nimmt eine Funktion auf, fügt einige Funktionen hinzu und gibt sie zurück. In diesem Tutorial erfahren Sie, wie Sie einen Decorator erstellen und warum Sie ihn verwenden sollten.
Video:@Decorators in Python
Dekorateure in Python
Python hat ein interessantes Feature namens Decorators um Funktionalität zu einem bestehenden Code hinzuzufügen.
Dies wird auch Metaprogrammierung genannt weil ein Teil des Programms versucht, einen anderen Teil des Programms zur Kompilierzeit zu modifizieren.
Voraussetzungen für das Erlernen von Dekorateuren
Um Decorators zu verstehen, müssen wir zuerst ein paar grundlegende Dinge in Python wissen.
Wir müssen uns damit abfinden, dass alles in Python (ja! sogar Klassen) Objekte sind. Namen, die wir definieren, sind einfach Bezeichner, die an diese Objekte gebunden sind. Funktionen sind keine Ausnahmen, sie sind auch Objekte (mit Attributen). An dasselbe Funktionsobjekt können verschiedene Namen gebunden werden.
Hier ist ein Beispiel.
def first(msg):
print(msg)
first("Hello")
second = first
second("Hello")
Ausgabe
Hello Hello
Wenn Sie den Code ausführen, funktionieren beide first
und second
die gleiche Ausgabe geben. Hier die Namen first
und second
beziehen sich auf dasselbe Funktionsobjekt.
Jetzt werden die Dinge seltsamer.
Funktionen können als Argumente an eine andere Funktion übergeben werden.
Wenn Sie Funktionen wie map
verwendet haben , filter
und reduce
in Python, dann wissen Sie bereits Bescheid.
Solche Funktionen, die andere Funktionen als Argumente annehmen, werden auch als Funktionen höherer Ordnung bezeichnet . Hier ist ein Beispiel für eine solche Funktion.
def inc(x):
return x + 1
def dec(x):
return x - 1
def operate(func, x):
result = func(x)
return result
Wir rufen die Funktion wie folgt auf.
>>> operate(inc,3)
4
>>> operate(dec,3)
2
Außerdem kann eine Funktion eine andere Funktion zurückgeben.
def is_called():
def is_returned():
print("Hello")
return is_returned
new = is_called()
# Outputs "Hello"
new()
Ausgabe
Hello
Hier, is_returned()
ist eine verschachtelte Funktion, die bei jedem Aufruf von is_called()
definiert und zurückgegeben wird .
Schließlich müssen wir Closures in Python kennen.
Zurück zu Dekorateuren
Funktionen und Methoden werden aufrufbar genannt wie sie genannt werden können.
Eigentlich jedes Objekt, das den speziellen __call__()
implementiert Methode wird als aufrufbar bezeichnet. Im einfachsten Sinne ist ein Decorator also ein Callable, das ein Callable zurückgibt.
Grundsätzlich nimmt ein Dekorateur eine Funktion auf, fügt einige Funktionen hinzu und gibt sie zurück.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
Wenn Sie die folgenden Codes in der Shell ausführen,
>>> ordinary()
I am ordinary
>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary
Im oben gezeigten Beispiel make_pretty()
ist Dekorateur. Im Zuweisungsschritt:
pretty = make_pretty(ordinary)
Die Funktion ordinary()
dekoriert und die zurückgegebene Funktion erhielt den Namen pretty
.
Wir können sehen, dass die Decorator-Funktion der ursprünglichen Funktion einige neue Funktionen hinzugefügt hat. Dies ist vergleichbar mit dem Verpacken eines Geschenks. Der Decorator fungiert als Wrapper. Die Art des dekorierten Objekts (das eigentliche Geschenk im Inneren) ändert sich nicht. Aber jetzt sieht es hübsch aus (seitdem es dekoriert wurde).
Im Allgemeinen dekorieren wir eine Funktion und weisen sie neu zu,
ordinary = make_pretty(ordinary).
Dies ist ein gängiges Konstrukt und aus diesem Grund hat Python eine Syntax, um dies zu vereinfachen.
Wir können den @
verwenden zusammen mit dem Namen der Decorator-Funktion und platzieren Sie es über der Definition der zu dekorierenden Funktion. Zum Beispiel
@make_pretty
def ordinary():
print("I am ordinary")
entspricht
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
Dies ist nur ein syntaktischer Zucker, um Dekorateure zu implementieren.
Funktionen mit Parametern dekorieren
Der obige Decorator war einfach und funktionierte nur mit Funktionen, die keine Parameter hatten. Was wäre, wenn wir Funktionen hätten, die Parameter annehmen wie:
def divide(a, b):
return a/b
Diese Funktion hat zwei Parameter, a und b . Wir wissen, dass es einen Fehler geben wird, wenn wir b übergeben als 0.
>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Lassen Sie uns nun einen Decorator erstellen, der diesen Fall prüft, der den Fehler verursacht.
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
Diese neue Implementierung gibt None
zurück wenn die Fehlerbedingung auftritt.
>>> divide(2,5)
I am going to divide 2 and 5
0.4
>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide
Auf diese Weise können wir Funktionen dekorieren, die Parameter annehmen.
Ein aufmerksamer Beobachter wird feststellen, dass die Parameter des verschachtelten inner()
Die Funktion innerhalb des Dekorators ist identisch mit den Parametern der Funktionen, die sie dekoriert. Unter Berücksichtigung dessen können wir jetzt allgemeine Dekorateure erstellen, die mit einer beliebigen Anzahl von Parametern arbeiten.
In Python wird diese Magie als function(*args, **kwargs)
ausgeführt . Auf diese Weise args
wird das Tupel aus Positionsargumenten und kwargs
sein wird das Wörterbuch der Schlüsselwortargumente sein. Ein Beispiel für einen solchen Dekorierer ist:
def works_for_all(func):
def inner(*args, **kwargs):
print("I can decorate any function")
return func(*args, **kwargs)
return inner
Verketten von Dekorateuren in Python
Mehrere Decorators können in Python verkettet werden.
Das heißt, eine Funktion kann mehrfach mit unterschiedlichen (oder gleichen) Dekorateuren dekoriert werden. Wir platzieren die Dekoratoren einfach über der gewünschten Funktion.
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%" * 30)
func(*args, **kwargs)
print("%" * 30)
return inner
@star
@percent
def printer(msg):
print(msg)
printer("Hello")
Ausgabe
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
Die obige Syntax von,
@star
@percent
def printer(msg):
print(msg)
entspricht
def printer(msg):
print(msg)
printer = star(percent(printer))
Die Reihenfolge, in der wir Dekorateure verketten, spielt eine Rolle. Wenn wir die Reihenfolge umgekehrt hätten als,
@percent
@star
def printer(msg):
print(msg)
Die Ausgabe wäre:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Python
- Python-Datentypen
- Python-Operatoren
- Python-pass-Anweisung
- Python-Funktionsargumente
- Anonyme Python/Lambda-Funktion
- Python-Lambda-Funktionen mit BEISPIELE
- Python abs() Funktion:Beispiele für absolute Werte
- Python-Funktion round() mit BEISPIELE
- Python range() Funktion:Float, List, For-Schleife Beispiele
- Python map() Funktion mit BEISPIELE