Direkt zum Inhalt
HeimAnleitungenPython

Python Dekoratoren Tutorial

In diesem Tutorial lernst du, wie man Dekoratoren in Python implementiert.
Aktualisierte 11. Sept. 2024  · 7 Min. lesen

Ein Dekorator ist ein Entwurfsmuster in Python, mit dem ein Benutzer einem bestehenden Objekt neue Funktionen hinzufügen kann, ohne seine Struktur zu verändern. Dekoratoren werden in der Regel auf Funktionen angewendet und spielen eine entscheidende Rolle bei der Verbesserung oder Änderung des Verhaltens von Funktionen. Traditionell werden Dekoratoren vor der Definition einer Funktion platziert, die du dekorieren möchtest. In diesem Lernprogramm zeigen wir dir, wie du Dekoratoren in Python-Funktionen effektiv einsetzen kannst.

Funktionen in Python sind Bürger erster Klasse. Das bedeutet, dass sie Operationen wie die Übergabe als Argument, die Rückgabe aus einer Funktion, die Änderung und die Zuweisung an eine Variable unterstützen. Diese Eigenschaft ist wichtig, da sie es ermöglicht, Funktionen wie jedes andere Objekt in Python zu behandeln, was eine größere Flexibilität bei der Programmierung ermöglicht.

Um den Beispielcode in diesem Lernprogramm ganz einfach selbst auszuführen, kannst du eine kostenlose DataLab-Arbeitsmappe erstellen, auf der Python vorinstalliert ist und die alle Codebeispiele enthält. Wenn du mehr über Dekoratoren erfahren möchtest, schau dir diese praktische DataCamp-Übung an.

Python von Grund auf lernen

Beherrsche Python für Data Science und erwerbe gefragte Fähigkeiten.
Kostenloses Lernen Beginnen

Zuweisung von Funktionen zu Variablen

Zu Beginn erstellen wir eine Funktion, die bei jedem Aufruf eine Eins zu einer Zahl addiert. Dann weisen wir die Funktion einer Variablen zu und verwenden diese Variable, um die Funktion aufzurufen.

def plus_one(number):
    return number + 1

add_one = plus_one
add_one(5)
6

Funktionen innerhalb anderer Funktionen definieren 

Als Nächstes zeigen wir dir, wie du eine Funktion innerhalb einer anderen Funktion in Python definieren kannst. Bleib dran, wir werden bald herausfinden, wie all das für die Erstellung und das Verständnis von Dekoratoren in Python relevant ist.

def plus_one(number):
    def add_one(number):
        return number + 1


    result = add_one(number)
    return result
plus_one(4)
5

Übergabe von Funktionen als Argumente an andere Funktionen

Funktionen können auch als Parameter an andere Funktionen übergeben werden. Das wollen wir im Folgenden veranschaulichen.

def plus_one(number):
    return number + 1

def function_call(function):
    number_to_add = 5
    return function(number_to_add)

function_call(plus_one)
6

Funktionen, die andere Funktionen zurückgeben

Eine Funktion kann auch eine andere Funktion erzeugen. Das zeigen wir weiter unten anhand eines Beispiels.

def hello_function():
    def say_hi():
        return "Hi"
    return say_hi
hello = hello_function()
hello()
'Hi'

Verschachtelte Funktionen haben Zugriff auf den Variablenbereich der einschließenden Funktion

Python erlaubt es einer verschachtelten Funktion, auf den äußeren Bereich der umschließenden Funktion zuzugreifen. Dies ist ein wichtiges Konzept bei Dekoratoren - dieses Muster wird als Closure bezeichnet.

def print_message(message):
    "Enclosong Function"
    def message_sender():
        "Nested Function"
        print(message)

    message_sender()

print_message("Some random message")
Some random message

Dekorateure schaffen

Nachdem diese Voraussetzungen geklärt sind, wollen wir einen einfachen Dekorator erstellen, der einen Satz in Großbuchstaben umwandelt. Wir tun dies, indem wir einen Wrapper innerhalb einer eingeschlossenen Funktion definieren. Wie du siehst, ist sie der Funktion innerhalb einer anderen Funktion, die wir zuvor erstellt haben, sehr ähnlich.

def uppercase_decorator(function):
    def wrapper():
        func = function()
        make_uppercase = func.upper()
        return make_uppercase

    return wrapper

Unsere Dekoratorfunktion nimmt eine Funktion als Argument an. Wir werden also eine Funktion definieren und sie an unseren Dekorator übergeben. Wir haben bereits gelernt, dass wir eine Funktion einer Variablen zuweisen können. Wir verwenden diesen Trick, um unsere Dekoratorfunktion aufzurufen.

def say_hi():
    return 'hello there'

decorate = uppercase_decorator(say_hi)
decorate()
'HELLO THERE'

Python bietet uns jedoch eine viel einfachere Möglichkeit, Dekoratoren anzuwenden. Wir verwenden einfach das @-Symbol vor der Funktion, die wir ausschmücken möchten. Das wollen wir im Folgenden in der Praxis zeigen.

@uppercase_decorator
def say_hi():
    return 'hello there'

say_hi()
'HELLO THERE'

Mehrere Dekoratoren auf eine einzige Funktion anwenden

Wir können mehrere Dekoratoren für eine einzige Funktion verwenden. Die Dekoratoren werden jedoch in der Reihenfolge angewendet, in der wir sie aufgerufen haben. Im Folgenden werden wir einen weiteren Dekorator definieren, der den Satz in eine Liste aufteilt. Dann wenden wir den uppercase_decorator und split_string Dekorator auf eine einzelne Funktion an.

import functools
def split_string(function):
    @functools.wraps(function)
    def wrapper():
        func = function()
        splitted_string = func.split()
        return splitted_string

    return wrapper 
@split_string
@uppercase_decorator
def say_hi():
    return 'hello there'
say_hi()
['HELLO', 'THERE']

Anhand der obigen Ausgabe sehen wir, dass die Anwendung der Dekoratoren von unten nach oben erfolgt. Hätten wir die Reihenfolge vertauscht, hätten wir einen Fehler gesehen, da Listen kein upper Attribut haben. Der Satz wurde zuerst in Großbuchstaben umgewandelt und dann in eine Liste aufgeteilt.

Hinweis: Beim Stapeln von Dekoratoren ist es gängige Praxis, functools.wraps zu verwenden, um sicherzustellen, dass die Metadaten der ursprünglichen Funktion während des Stapelvorgangs erhalten bleiben. Das hilft bei der Fehlersuche und dem Verständnis der Eigenschaften der dekorierten Funktion, Klarheit und Konsistenz zu bewahren.

Akzeptieren von Argumenten in Decorator-Funktionen

Manchmal müssen wir vielleicht einen Dekorator definieren, der Argumente akzeptiert. Wir erreichen dies, indem wir die Argumente an die Wrapper-Funktion übergeben. Die Argumente werden dann an die Funktion übergeben, die zum Zeitpunkt des Aufrufs dekoriert wird.

def decorator_with_arguments(function):
    def wrapper_accepting_arguments(arg1, arg2):
        print("My arguments are: {0}, {1}".format(arg1,arg2))
        function(arg1, arg2)
    return wrapper_accepting_arguments


@decorator_with_arguments
def cities(city_one, city_two):
    print("Cities I love are {0} and {1}".format(city_one, city_two))

cities("Nairobi", "Accra")

My arguments are: Nairobi, Accra Cities I love are Nairobi and Accra

Hinweis: Es ist wichtig sicherzustellen, dass die Anzahl der Argumente im Dekorator (arg1, arg2 in diesem Beispiel) mit der Anzahl der Argumente in der umschlossenen Funktion (cities in diesem Beispiel) übereinstimmt. Diese Ausrichtung ist wichtig, um Fehler zu vermeiden und die korrekte Funktionalität bei der Verwendung von Dekoratoren mit Argumenten sicherzustellen.

Definition von Allzweckdekoratoren

Um einen Allzweckdekorator zu definieren, der auf jede Funktion angewendet werden kann, verwenden wir args und **kwargs. args und **kwargs sammeln alle Positions- und Schlüsselwortargumente und speichern sie in den Variablen args und kwargs. args und kwargs ermöglichen es uns, bei Funktionsaufrufen so viele Argumente zu übergeben, wie wir möchten.

def a_decorator_passing_arbitrary_arguments(function_to_decorate):
    def a_wrapper_accepting_arbitrary_arguments(*args,**kwargs):
        print('The positional arguments are', args)
        print('The keyword arguments are', kwargs)
        function_to_decorate(*args)
    return a_wrapper_accepting_arbitrary_arguments

@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
    print("No arguments here.")

function_with_no_argument()
The positional arguments are ()
The keyword arguments are {}
No arguments here.

Schauen wir uns an, wie wir den Dekorator mit Positionsargumenten verwenden können.

@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
    print(a, b, c)

function_with_arguments(1,2,3)
The positional arguments are (1, 2, 3)
The keyword arguments are {}
1 2 3

Schlüsselwortargumente werden mit Schlüsselwörtern übergeben. Eine Illustration dazu findest du unten.

@a_decorator_passing_arbitrary_arguments
def function_with_keyword_arguments():
    print("This has shown keyword arguments")

function_with_keyword_arguments(first_name="Derrick", last_name="Mwiti")
The positional arguments are ()
The keyword arguments are {'first_name': 'Derrick', 'last_name': 'Mwiti'}
This has shown keyword arguments

Hinweis: Die Verwendung von **kwargs im Dekorator ermöglicht es, Schlüsselwortargumente zu behandeln. Dadurch ist der Allzweckdekorator vielseitig und kann eine Vielzahl von Argumenttypen bei Funktionsaufrufen verarbeiten.

Übergabe von Argumenten an den Decorator

Schauen wir uns nun an, wie wir Argumente an den Dekorator selbst übergeben. Um dies zu erreichen, definieren wir einen Dekorator-Maker, der Argumente akzeptiert, und definieren dann einen Dekorator in ihm. Dann definieren wir eine Wrapper-Funktion innerhalb des Dekorators, so wie wir es zuvor getan haben.

def decorator_maker_with_arguments(decorator_arg1, decorator_arg2, decorator_arg3):
    def decorator(func):
        def wrapper(function_arg1, function_arg2, function_arg3) :
            "This is the wrapper function"
            print("The wrapper can access all the variables\n"
                  "\t- from the decorator maker: {0} {1} {2}\n"
                  "\t- from the function call: {3} {4} {5}\n"
                  "and pass them to the decorated function"
                  .format(decorator_arg1, decorator_arg2,decorator_arg3,
                          function_arg1, function_arg2,function_arg3))
            return func(function_arg1, function_arg2,function_arg3)

        return wrapper

    return decorator

pandas = "Pandas"
@decorator_maker_with_arguments(pandas, "Numpy","Scikit-learn")
def decorated_function_with_arguments(function_arg1, function_arg2,function_arg3):
    print("This is the decorated function and it only knows about its arguments: {0}"
           " {1}" " {2}".format(function_arg1, function_arg2,function_arg3))

decorated_function_with_arguments(pandas, "Science", "Tools")
The wrapper can access all the variables
    - from the decorator maker: Pandas Numpy Scikit-learn
    - from the function call: Pandas Science Tools
and pass them to the decorated function
This is the decorated function, and it only knows about its arguments: Pandas Science Tools

Debuggen von Dekoratoren

Wie wir gesehen haben, umhüllen Dekoratoren Funktionen. Der ursprüngliche Funktionsname, der Docstring und die Parameterliste werden von der Wrapper-Schließung verborgen: Wenn wir zum Beispiel versuchen, auf die Metadaten von decorated_function_with_arguments zuzugreifen, sehen wir die Metadaten der Wrapper-Schließung. Dies stellt eine Herausforderung bei der Fehlersuche dar.

decorated_function_with_arguments.__name__
'wrapper'
decorated_function_with_arguments.__doc__
'This is the wrapper function'

Um diese Herausforderung zu lösen, bietet Python einen functools.wraps Dekorator. Dieser Dekorator kopiert die verlorenen Metadaten von der undekorierten Funktion in die dekorierte Schließung. Lass uns zeigen, wie wir das machen würden.

import functools

def uppercase_decorator(func):
    @functools.wraps(func)
    def wrapper():
        return func().upper()
    return wrapper
@uppercase_decorator
def say_hi():
    "This will say hi"
    return 'hello there'

say_hi()
'HELLO THERE'

Wenn wir die Metadaten von say_hi überprüfen, stellen wir fest, dass sie sich jetzt auf die Metadaten der Funktion beziehen und nicht auf die Metadaten des Wrappers.

say_hi.__name__
'say_hi'
say_hi.__doc__
'This will say hi'

Es ist ratsam und gute Praxis, bei der Definition von Dekoratoren immer functools.wraps zu verwenden. Das erspart dir eine Menge Kopfschmerzen bei der Fehlersuche.

Python-Dekoratoren Zusammenfassung

Decorators verändern dynamisch die Funktionalität einer Funktion, Methode oder Klasse, ohne direkt Unterklassen zu verwenden oder den Quellcode der zu dekorierenden Funktion zu ändern. Die Verwendung von Dekoratoren in Python stellt außerdem sicher, dass dein Code DRY (Don't Repeat Yourself) ist. Dekoratoren haben mehrere Anwendungsfälle, wie zum Beispiel:

  • Autorisierung in Python-Frameworks wie Flask und Django
  • Loggen
  • Messung der Ausführungszeit
  • Synchronisation

Mehr über Python-Dekoratoren erfährst du in der Python-Dekorator-Bibliothek.

Themen

Erfahre mehr über Python

Course

Writing Functions in Python

4 hr
88.8K
Learn to use best practices to write maintainable, reusable, complex functions with good documentation.
See DetailsRight Arrow
Start Course
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Die 32 besten AWS-Interview-Fragen und Antworten für 2024

Ein kompletter Leitfaden zur Erkundung der grundlegenden, mittleren und fortgeschrittenen AWS-Interview-Fragen, zusammen mit Fragen, die auf realen Situationen basieren. Es deckt alle Bereiche ab und sorgt so für eine abgerundete Vorbereitungsstrategie.
Zoumana Keita 's photo

Zoumana Keita

30 Min.

See MoreSee More