Über Python-Dekorateure

Dieses Mal werde ich über Python-Dekorateure sprechen.

Einführung.

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.

Was ist ein Dekorateur?

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.

Ein einfaches Beispiel für einen Dekorateur

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.

Eine kurze Beschreibung von Nakami

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)

Was kann man also mit einem Dekorateur machen?

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.

Beispiel Dekorator in einer Methode mit einem Rückgabewert

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.

Was bedeutet das

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.

Nestdekorateure

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

Dekorieren Sie eine Methode mit Argumenten

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.

Geben Sie das Argument an den Dekorateur weiter

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.

Ende

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.

Postscript 2018.7.6

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.

Ein anderes Beispiel

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

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.

Referenz-URL

Recommended Posts

Über Python Decorator
Über Python-Dekorateure
Über Python-Slices
Über die Einschlussnotation von Python
Über Python tqdm.
Über die Python-Ausbeute
Über Python, Klasse
Informationen zur Python-Vererbung
Über Python, range ()
[Python] Über Multi-Prozess
Über Python für Schleife
[Python] Memo über Funktionen
Zusammenfassung über Python3 + OpenCV3
Über Python für ~ (Bereich)
[Python] Memo Über Fehler
Informationen zur Python-Entwicklungsumgebung
Python: Über Funktionsargumente
Python, über die Ausnahmebehandlung
Über Python Pyramid Traversal
Über Python3 ... (Ellipsenobjekt)
[Python] Kapitel 01-01 Über Python (Erster Python)
[Python] Informationen zur Standardeingabe
Über __all__ in Python
[Python] Informieren Sie sich über pip
Fabric unterstützt Python 3
Python
Informationen zu Python-Objekten und -Klassen
Informationen zu Python-Variablen und -Objekten
Über das Python-Modul venv
Python-Anfänger-Memorandum-Funktion
Über die Aufzählungsfunktion (Python)
Über verschiedene Codierungen von Python 3
Über Python, len () und randint ()
Über Perl, Python, PHP, Ruby
Informationen zu Python-Datums- und Zeitzone
Memorandum über Korrelation [Python]
Ein Memorandum über den Python-Mock
Informationen zu Python-Zeichenfolgenvergleichsoperatoren
Über Python und reguläre Ausdrücke
Über die Funktionen von Python
Über "für _ in range ():" von Python
Informationen zu Python- und Betriebssystemoperationen
Python # Über Referenz und Kopie
Über Python sort () und reverse ()
Ein Hinweis zu [Python] __debug__
Initialisierung globaler Variablen mit Python-Dekoratoren
Python Hinweis: Über den Vergleich mit is
Informationen zur Installation der Serien Pwntools und Python2
Python: Ein Hinweis zu Klasse 1 "Abstract"
[Python] Lassen Sie uns kurz über die Einschlussnotation schreiben
Über Python-Diktat und sortierte Funktionen
[Python] Was ist @? (Über Dekorateure)
Was war überraschend an Python-Klassen?
[Python] Was sind @classmethod und Dekorateure?
[Python] Über Executor und zukünftige Klassen
Über Python, aus und importieren, als
Ich habe versucht, den Prozess mit Python zu studieren