English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Der Dekorator akzeptiert eine Funktion, fügt einige Funktionen hinzu und gibt sie zurück. In diesem Artikel werden Sie lernen, wie man Dekorateure erstellt und warum man sie verwendet.
Python hat eine interessante Funktion namensDekoratorengenannt, kann Funktionen zu vorhandener Code hinzufügen.
Das wird auchMetaprogrammierung,Weil ein Teil des Programms versucht, ein anderes Teil des Programms während der Kompilierung zu ändern.
Um Dekoratoren zu verstehen, müssen wir zunächst einige grundlegende Kenntnisse in Python haben.
Wir müssen akzeptieren, dass alles in PythonObjekte. Die von uns definierten Namen sind nur Bezeichner für diese Objekte.FunktionenDas gilt auch, sie sind ebenfalls Objekte (mit Eigenschaften). Various different names can be bound to the same functional object.
Dies ist ein Beispiel.
def first(msg): print(msg) first("Hello") second = first second("Hello")
Wenn Sie das Code ausführen, geben die beiden Funktionen first und second die gleiche Ausgabe zurück. Hier beziehen sich die Namen first und second auf das gleiche Funktionsobjekt.
Jetzt fühlt es sich vielleicht etwas komplizierter an, Funktionen als Parameter an eine andere Funktion zu übergeben.
Wenn Sie in Python map, filter und reduce usw. verwendet haben, dann wissen Sie das bereits.
Diese Funktionen, die andere Funktionen als Parameter akzeptieren, werden auchHöhere Funktionen. Dies 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
Darüber hinaus kann eine Funktion eine andere Funktion zurückgeben.
def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() # Ausgabe "Hello" new()
Hier ist is_returned() eine eingebettete Funktion, die jedes Mal definiert und zurückgegeben wird, wenn wir is_drawn() aufrufen.
Schließlich müssen wir verstehenKlammern in Python.
Funktionen und Methoden werden alsAufrufbar,Weil sie aufgerufen werden können.
In der Tat wird jedes Objekt, das die spezielle Methode __call__() implementiert, als aufrufbar bezeichnet. Daher sind Dekoratoren im wörtlichen Sinne aufrufbar und können aufrufbare Objekte zurückgeben.
Grundsätzlich akzeptieren Dekoratoren eine Funktion, fügen einige Funktionen hinzu und geben sie zurück.
def make_pretty(func): def inner(): print("Ich wurde dekoriert") func() return inner def ordinary(): print("Ich bin eine gewöhnliche Funktion")
Wenn Sie den folgenden Code im Shell ausführen:
>>> ordinary() Ich bin eine gewöhnliche Funktion >>> # Wir dekorieren diese gewöhnliche Funktion >>> pretty = make_pretty(ordinary) >>> pretty() Ich wurde dekoriert Ich bin eine gewöhnliche Funktion
Im gezeigten Beispiel ist make_pretty() ein Dekorator im Zuweisungsschritt.
pretty = make_pretty(ordinary)
Die Funktion ordinary() wurde dekoriert und die zurückgegebene Funktion heißt pretty.
Wir können sehen, dass der Dekorator-Funktion neue Funktionen hinzufügt, die im ursprünglichen Funktion hinzugefügt werden. Dies ist ähnlich wie das Verpacken eines Geschenks. Der Dekorator fungiert als Verpackung. Die Eigenschaften des dekorierten Gegenstands (des Geschenks innen) ändern sich nicht. Aber jetzt sieht es schön aus (seit dem Dekorieren).
Normalerweise dekorieren wir eine Funktion und zuweisen sie neu,
ordinary = make_pretty(ordinary).
Dies ist eine häufige Konstruktion, daher hat Python eine Syntax zur Vereinfachung dieser Konstruktion.
Wir können das @-Zeichen zusammen mit dem Namen des Dekorator-Funktion verwenden und es über der Definition der zu dekorierenden Funktion platzieren. Zum Beispiel:
@make_pretty def ordinary(): print("Ich bin eine gewöhnliche Funktion")
entspricht
def ordinary(): print("Ich bin eine gewöhnliche Funktion") ordinary = make_pretty(ordinary)
Dies ist nur ein Syntax-Hinweis für die Implementierung von Dekoratoren.
Der obige Dekorator ist einfach und nur für Funktionen ohne Parameter geeignet. Was machen wir, wenn unsere Funktion wie folgt parameterisiert ist?
def divide(a, b): return a/b
Diese Funktion hat zwei Parameter,aundb. Wir wissen, dass wenn wirbWenn 0 übergeben wird, wird ein Fehler verursacht.
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last): ... ZeroDivisionError: Division durch Null
Lassen Sie uns einen Dekorator schreiben, um zu überprüfen, ob dies zu einem Fehler führt.
def smart_divide(func): def inner(a,b): print("Ich mache Division von", a, "und", b) if b == 0: print("Ach! Division durch Null ist nicht möglich") return return func(a,b) return inner @smart_divide def divide(a,b): return a/b
Falls ein Fehler auftritt, wird diese neue Implementierung None zurückgeben.
>>> divide(2,5) Ich mache Division 2 und 5 0.4 >>> divide(2,0) Ich mache Division 2 und 0 Oh nein! Division nicht möglich
Auf diese Weise können wir Funktionen mit Parametern dekorieren.
Genau beobachtende Beobachter werden bemerken, dass die Parameter der verschachtelten Funktion im Innern des inner() Dekorators mit den Parametern der dekorierten Funktion übereinstimmen. Unter Berücksichtigung dessen können wir jetzt universelle Dekorationen mit einer beliebigen Anzahl von Parametern verwenden.
In Python wird dieses Magie durch das Beenden der function(*args, **kwargs). Auf diese Weise sind args die PositionalsparameterTupelstatt der PositionalsparameterDictionnaire. Ein Beispiel für solche Dekorationen ist.
def works_for_all(func): def inner(*args, **kwargs): Ich kann jede Funktion dekorieren return func(*args, **kwargs) return inner
Es können mehrere Dekorationen in Python verknüpft werden.
Das bedeutet, dass eine Funktion mehrmals mit verschiedenen (oder gleichen) Dekorationen dekoriert werden kann. Wir müssen nur die Dekorationen über der benötigten Funktion platzieren.
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("Hallo")
Das gibt den Ausgang.
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hallo %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
obiger Syntax
@star @percent def printer(msg): print(msg)
entspricht
def printer(msg): print(msg) printer = star(percent(printer))
Die Reihenfolge der Verknüpfung von Verknüpfungsdekorationen ist wichtig. Wenn wir in umgekehrter Reihenfolge vorgehen:
@percent @star def printer(msg): print(msg)
Die Ausführung wird erfolgen
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hallo ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%