Dieses Mal werde ich über Python-Dekorateure sprechen.
Während des Studiums zusammen mit der Python-Programmierung [^ experten_python] kam das Konzept der Python-Dekoratoren auf. Ich habe nicht verstanden, was ich im Inhalt des Buches gesagt habe, also habe ich viel recherchiert.
[^ expart_python]: Expert Python Programming Revised 2nd Edition wurde am 26. Februar 2018 veröffentlicht. Für diejenigen, die von nun an studieren, wird die 2. Ausgabe empfohlen.
Dekorieren ist eine Modifikation. Ein Dekorateur ist jedoch einfach eine Funktion zum Ändern einer bestimmten Funktion und ihres Mechanismus. Angenommen, Sie haben eine Funktion. Werfen wir einen Blick auf die folgende test () -Funktion und ihr Ausführungsskript.
Beispielskript 1
test.py
def test():
print('Hello Decorator')
test()
Das Ausführungsergebnis ist wie folgt.
Hello Decorator
Nun, es ist natürlich.
Wir werden diese Testfunktion dekorieren.
Das obige Skript ist mit einem Dekorateur dekoriert:
sample_deco1.py
def deco(func):
def wrapper(*args, **kwargs):
print('--start--')
func(*args, **kwargs)
print('--end--')
return wrapper
@deco
def test():
print('Hello Decorator')
test()
Das Ausführungsergebnis ist wie folgt.
--start--
Hello Decorator
--end--
Nun wollen wir sehen, was das los ist.
Die 1. Zeile def deco (func):
zur 6. Zeile return wrapper
ist die Dekorationsdefinitionsfunktion zum Dekorieren. Nach dieser Funktion dekorieren. Die 8. Zeile "@ deco" verziert die folgende Funktion mit der Definitionsfunktion des Dekorateurs "deco". Es wird sein.
Lassen Sie uns nun über den Inhalt der Dekorationsdefinitionsfunktion sprechen.
Das Wichtigste ist die 3. Zeile print ('--start -')
bis zur 5. Zeile print ('--end -')
.
Zeile 1 def deco (func):
ist die Deklaration der Decorator-Funktion. Obwohl func als Argument angegeben wird, wird die dekorierte Funktion test ()
selbst als Argument übergeben.
Zeile 2 def wrapper (* args, ** kwargs):
ist eine Funktion zum Schreiben des Inhalts des eigentlichen Dekorateurs. Wenn Sie nicht gut verstehen, lassen Sie uns fortfahren, während wir diese Art von Dingen erfassen. Ich werde später im Detail erklären.
Nun die wichtige 3. bis 5. Zeile.
Die vierte Zeile, func (* args, ** kwargs)
, führt die als Argument übergebene Funktion aus.
In der 3. Zeile print ('--start -')
und der 6. Zeile print ('--end -')
, der 5. Zeile func (* args, ** kwargs)
Gibt die Verarbeitung an, die vorher und nachher ausgeführt werden soll.
Also, * args, ** kwargs
sind die Argumente der zu dekorierenden Funktion. Nun, es ist in Ordnung, wenn Sie eine solche Funktion schreiben, ohne darüber nachzudenken (vielleicht)
Mit dem Dekorator können Sie die Verarbeitung vor und nach der Verarbeitung der vorhandenen Funktion selbst hinzufügen. Ich dachte darüber nach, was für eine Situation ich tun sollte. Ich selbst habe noch nicht viel gelernt, aber mithilfe von Dekoratoren kann ich eine Verarbeitung hinzufügen, die automatisch ausgeführt wird, wenn eine als Bibliothek bereitgestellte Funktion aufgerufen wird. Ich werde.
In Python ist es möglich, die Funktion selbst in Form einer in Java usw. verwendeten Überschreibung neu zu schreiben. Es gibt jedoch kein Problem mit der vorhandenen Verarbeitung, aber ich möchte auch gleichzeitig eine andere Verarbeitung durchführen. Ich denke, dass der Dekorateur in einer solchen Situation eingesetzt wird.
Als ich recherchierte, wurde ich in ein Programm eingeführt, das einen Dekorateur verwendet, um eine bestimmte Funktion zu bewerten.
Nun, sobald Sie eine Dekorationsfunktion für den Benchmark erstellt haben, können Sie jeden Benchmark messen, indem Sie verschiedene Funktionen mit @ dekorieren. Es ist bequem.
Im obigen Beispiel hatte die dekorierte Methode keinen Rückgabewert. Aber natürlich haben Methoden manchmal einen Rückgabewert. Hier ist ein Beispiel für einen Dekorator für eine Methode mit einem Rückgabewert.
sample_deco2.py
def deco2(func):
import os
def wrapper(*args,**kwargs):
res = '--start--' + os.linesep
res += func(*args,**kwargs) + '!' + os.linesep
res += '--end--'
return res
return wrapper
@deco2
def test2():
return('Hello Decorator')
print(test2())
Das Ausführungsergebnis dieses Skripts lautet wie folgt.
--start--
Hello Decorator!
--end--
Ah! ?? Das Ergebnis der Ausführung hat sich nicht geändert! !! Was? Nein, es hat sich leicht verändert. Ein Teil der Ausgabe wurde von "Hello Decorator" in "Hello Decorator!" Geändert. Der Inhalt des Programms hat sich erheblich geändert. Ich werde dieses Programm erklären, während ich es mit dem vorherigen Programm vergleiche.
Erstens hat die dekorierte Methode def test2 ():
im Vergleich zum vorherigen Programm jetzt einen String-Rückgabewert return'Hello Decorator'
. Und print (test2 ())
druckt die zurückgegebene Zeichenfolge.
Früher war die zu dekorierende Methode eine Methode zur Ausgabe einer Zeichenfolge, diesmal ist die zu dekorierende Methode eine Methode zur Erzeugung einer Zeichenfolge. Wenn Sie eine Methode dekorieren, die etwas erzeugt, müssen Sie den Dekorator so schreiben, dass das generierte Ergebnis zurückgegeben wird.
Wir werden einen anderen Ort als den vorherigen im Inhalt des Dekorateurs auswählen.
Zeile 5 res = func (* args, ** kwargs) + '!'
Zeile 7 return res
Zeile 8 "Return Wrapper"
In der 5. Zeile wird "func (** kwargs)" ausgeführt und "!" Am Ende der zurückgegebenen Zeichenfolge hinzugefügt und in "res" gespeichert. Zeile 7 gibt "res" zurück. Es wird an die Methode zurückgegeben, die in Zeile 8 mit dem "Return Wrapper" weiter dekoriert ist.
Ein Dekorator bedeutet, dass Sie nicht nur eine Methode dekorieren können, die einen Wert zurückgibt, sondern auch den Rückgabewert der Methode, die Sie dekorieren, verarbeiten können. Das ist sehr interessant. Wenn Sie der Meinung sind, dass es möglich ist, dem Ausgabeergebnis des Dekorationsprogramms einen bestimmten Prozess hinzuzufügen ...? Es wird eine Menge Spass machen.
Darüber hinaus können beispielsweise in Tags wie html und xml eingeschlossene Notationen mit einer Methode beschrieben werden, die nur den Inhalt mithilfe eines Dekorators generiert.
Das? Wenn Sie beispielsweise HTML mit einem Dekorateur schreiben, möchten Sie es verschachteln ... Ja. Dekorateure können auch verschachtelt werden.
Es ist auch möglich, mehrere Dekorateure zu kombinieren. Zum Beispiel ist die Situation wie folgt.
deco_sample3.py
def deco_html(func):
def wrapper(*args, **kwargs):
res = '<html>'
res = res + func(*args, **kwargs)
res = res + '</html>'
return res
return wrapper
def deco_body(func):
def wrapper(*args, **kwargs):
res = '<body>'
res = res + func(*args, **kwargs)
res = res + '</body>'
return res
return wrapper
@deco_html
@deco_body
def test():
return 'Hello Decorator'
print(test())
Das Ausführungsergebnis ist wie folgt.
<html><body>Hello Decorator!</body></html>
Dieses Programm ist nicht schwierig, wenn Sie die vorherigen Programme kennen. Es gibt nur zwei Dekorateure, die def test (str) dekorieren:
. Es wird in der Reihenfolge von unten verarbeitet.
Es wird ziemlich lustig. Es scheint, dass Dekorateure verschiedene Dinge tun können. Das? Ist es übrigens nicht möglich, einen Dekorator für eine Methode mit Argumenten zu verwenden? Ich kann es schaffen
Erstellen Sie die Dekoration der Methode mit dem folgenden Argument.
deco_sample4.py
def deco_p(func):
def wrapper(*args, **kwargs):
res = '<p>'
res = res + func(args[0], **kwargs)
res = res + '</p>'
return res
return wrapper
@deco_p
def test(str):
return str
print(test('Hello Decorator!'))
Das Ausführungsergebnis ist wie folgt.
<p>Hello Decorator!</p>
Was ist übrigens der Unterschied zum vorherigen Programm?
Es ist func (args [0], ** kwargs)
. Tatsächlich ist der Dekorateur bereit, Argumente zu empfangen, unabhängig davon, ob die Dekorationsmethode Argumente enthält. Wenn Sie ein Argument verwenden möchten, nehmen Sie das Argument aus "args" und übergeben Sie es an "func". Und was interessant ist, ist, dass "args" ein Tapple ist.
Was bedeutet es, ein Taple zu sein? Derzeit kann zumindest die integrierte Methode len () verwendet werden. Dies bedeutet, dass Sie das Verhalten des Dekorateurs abhängig von der Anzahl der Argumente ändern können. Ich frage mich, ob ich es überhaupt als Argument an den Dekorateur weitergeben kann ... Sie können es bestehen.
deco_sample5.py
def deco_tag(tag):
def _deco_tag(func):
def wrapper(*args, **kwargs):
res = '<'+tag+'>'
res = res + func(*args, **kwargs)
res = res + '</'+tag+'>'
return res
return wrapper
return _deco_tag
@deco_tag('html')
@deco_tag('body')
def test():
return 'Hello Decorator!'
print(test())
Das Ausgabeergebnis ist wie folgt.
<html><body>Hello Decorator!</body></html>
Ich werde es nicht müde werden, aber hier niste ich Dekorateure.
Dieses Mal habe ich verschiedene Dekorateure ausprobiert und den Inhalt hier geschrieben. Dekorateure sind interessant. Ich denke, ich kann verschiedene Dinge tun. Wenn Sie dies beispielsweise mit einem Generator kombinieren, können Sie anscheinend wirklich verschiedene Dinge tun. Die Referenz-URL, die ich ganz am Anfang geschrieben habe, enthält eine detailliertere Erklärung des Dekorateurs. Wenn Sie also interessiert sind, bitte.
Bis bald.
Ich habe diesen Artikel im Januar 2015 geschrieben. Es ist dreieinhalb Jahre her, seit es veröffentlicht wurde, und ich bin dankbar, dass es immer noch Leute gibt, die den Artikel mögen. Nach dreieinhalb Jahren bekam ich auch ein besseres Verständnis für Python-Dekorateure.
Ich werde eine Geschichte hinzufügen, die jetzt gemacht werden kann.
Ich habe damals nicht daran gedacht, aber jetzt zeige ich Ihnen, wie man es mit einem Dekorateur benutzt. (Ich weiß nicht, ob ich es tatsächlich tun werde)
Zum Beispiel, wenn Sie die folgenden Module haben:
my_method.py
def my_method(*args, **kwargs):
if 'test_key' in kwargs:
print('test_Der Wert des Schlüssels ist[{}]'.format(kwargs['test_key']))
else:
print('test_Der Schlüssel enthält keinen Wert.')
my_method()
my_method(test_key="Wert zum Testen")
Das Ausführungsergebnis des Moduls ist wie folgt.
test_Der Schlüssel enthält keinen Wert.
test_Der Wert des Schlüssels ist[Wert zum Testen]
Sie können das Verhalten auf einmal ändern, indem Sie den Dekorator verwenden.
my_method_2.py
def my_decorator(target_function):
def wrapper_function(*args, **kwargs):
kwargs['test_key'] = 'Wert vom Dekorateur umgeschrieben'
return target_function(*args, **kwargs)
return wrapper_function
@my_decorator
def my_method(*args, **kwargs):
if 'test_key' in kwargs:
print('test_Der Wert des Schlüssels ist[{}]'.format(kwargs['test_key']))
else:
print('test_Der Schlüssel enthält keinen Wert.')
my_method()
my_method(test_key="Wert zum Testen")
Das Ausführungsergebnis ist wie folgt.
test_Der Wert des Schlüssels ist[Wert vom Dekorateur umgeschrieben]
test_Der Wert des Schlüssels ist[Wert vom Dekorateur umgeschrieben]
Sie können die Argumente auf einmal so ändern. Wofür verwendest du es? Ich bekomme kein gutes Beispiel, um darauf zu antworten, aber ich denke, es ist gut zu wissen, dass Sie dies auch tun können.
Der Dekorateur ist Syntax Sugar. Syntaxzucker ist eine Grammatik, die das Schreiben von Programmen für bestimmte Zwecke erleichtert. Nicht nur auf Python beschränkt, es gibt auch Syntaxzuckergrammatiken in anderen Sprachen.
Ein Syntaxzucker zu sein bedeutet, dass es eine andere Möglichkeit gibt, ihn zu schreiben.
Zum Beispiel, wenn Sie die folgenden Module haben:
def twice(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) * 2
return wrapper
@twice
def add(x, y):
return x + y
print(add(1, 3))
Das Ergebnis dieser Ausführung ist das gleiche wie das Ergebnis der nächsten Ausführung.
def twice(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs) * 2
return wrapper
def add(x, y):
return x + y
print(twice(add)(1, 3))
Ich habe die Add-Funktion an die zweimal aufgerufene Funktion übergeben und "1, 3" an die Funktion übergeben, die herauskam und das Ergebnis der Ausführung druckte.
Es ist schwer zu verstehen, was Sie tun möchten, wenn Sie es so schreiben. Deshalb denke ich, dass der Dekorateur geschaffen wurde.
Recommended Posts