Dekoratoren in Python

Dekoratoren in Python

Dieser Artikel erklärt Dekoratoren in Python.

YouTube Video

Dekoratoren in Python

Python-Dekoratoren sind eine leistungsstarke Funktion, die verwendet wird, um Funktionen oder Methoden zusätzliche Funktionalitäten hinzuzufügen. Dekoratoren ermöglichen es, neue Funktionalitäten hinzuzufügen, ohne den bestehenden Code zu verändern, was die Wiederverwendbarkeit und Wartbarkeit des Codes verbessert.

Grundlagen der Dekoratoren

Python-Dekoratoren funktionieren, indem sie eine Funktion als Argument nehmen und eine neue Funktion mit zusätzlicher Funktionalität zurückgeben. Mit Dekoratoren können Sie Vor- oder Nachbearbeitungen leicht zu Funktionen hinzufügen.

Ohne Dekoratoren erfordert das Ändern des Verhaltens einer Funktion, dass die Funktion selbst direkt bearbeitet wird. Mit Dekoratoren können Sie die Funktionalität erweitern, ohne die ursprüngliche Implementierung zu ändern.

Grundlegende Struktur eines Dekorators

 1def my_decorator(func):
 2    def wrapper():
 3        print("Before the function call")
 4        func()
 5        print("After the function call")
 6    return wrapper
 7
 8@my_decorator
 9def say_hello():
10    print("Hello!")
11
12say_hello()

In diesem Beispiel dient die Funktion my_decorator als Dekorator und umschließt die Funktion say_hello. Der Dekorator wird mit der Syntax @my_decorator angewendet, und wenn say_hello() aufgerufen wird, wird die vom Dekorator bereitgestellte Vor- und Nachbearbeitung automatisch ausgeführt.

Wie Dekoratoren funktionieren

Dekoratoren funktionieren in den folgenden Schritten.

  1. Der Dekorator nimmt eine Funktion (oder Methode) als Argument.

  2. Er definiert eine Wrapper-Funktion, um die ursprüngliche Funktion auszuführen.

  3. Die Wrapper-Funktion führt zusätzliche Verarbeitung vor oder nach der Ausführung der ursprünglichen Funktion durch.

  4. Der Dekorator gibt die Wrapper-Funktion zurück. Das Ergebnis ist, dass die ursprüngliche Funktion durch eine neue, dekorierte Funktion ersetzt wird.

Dekoratoren für Funktionen mit Argumenten

Wenn ein Dekorator auf eine Funktion mit Argumenten angewendet wird, muss die Wrapper-Funktion so angepasst werden, dass sie diese Argumente akzeptiert.

 1def my_decorator(func):
 2    def wrapper(*args, **kwargs):
 3        print("Before the function call")
 4        result = func(*args, **kwargs)
 5        print("After the function call")
 6        return result
 7    return wrapper
 8
 9@my_decorator
10def greet(name):
11    print(f"Hello, {name}!")
12
13greet("Alice")

Durch die Verwendung von *args und **kwargs ist es möglich, Funktionen zu behandeln, die eine beliebige Anzahl von Argumenten und Schlüsselwort-Argumenten akzeptieren. Dies ermöglicht es, Dekoratoren generisch auf Funktionen mit beliebigen Arten von Argumenten anzuwenden.

Beispiele für die Anwendung von Dekoratoren

Dekorator für Logging

Dekoratoren werden oft verwendet, um Logging-Funktionalitäten hinzuzufügen. Zum Beispiel kann durch die Erstellung eines Dekorators, der vor und nach der Ausführung einer Funktion Logdaten erfasst, aufgezeichnet werden, wann die Funktion aufgerufen wird und wie lange sie zur Ausführung benötigt.

 1import time
 2
 3def log_time(func):
 4    def wrapper(*args, **kwargs):
 5        start_time = time.time()
 6        print(f"Calling function '{func.__name__}'...")
 7        result = func(*args, **kwargs)
 8        end_time = time.time()
 9        print(f"Function '{func.__name__}' completed in {end_time - start_time} seconds")
10        return result
11    return wrapper
12
13@log_time
14def long_task(duration):
15    time.sleep(duration)
16    print("Task completed!")
17
18long_task(2)

In diesem Beispiel misst der log_time-Dekorator die Ausführungszeit einer Funktion und gibt sie als Log aus. Die Funktion long_task wird mit dem Dekorator umhüllt, und ihre Ausführungszeit wird zur Laufzeit aufgezeichnet.

Dekorator für die Berechtigungsverwaltung

Dekoratoren können auch für die Berechtigungsverwaltung verwendet werden. Zum Beispiel kann die Verarbeitung eingeschränkt werden, indem geprüft wird, ob ein Benutzer bestimmte Berechtigungen besitzt.

 1def requires_permission(user_role):
 2    def decorator(func):
 3        def wrapper(*args, **kwargs):
 4            if user_role != "admin":
 5                print("Permission denied!")
 6                return
 7            return func(*args, **kwargs)
 8        return wrapper
 9    return decorator
10
11@requires_permission("admin")
12def delete_user(user_id):
13    print(f"User {user_id} has been deleted.")
14
15delete_user(123)  # Executed
16delete_user = requires_permission("guest")(delete_user)
17delete_user(456)  # Permission denied!

Der Dekorator requires_permission schränkt die Ausführung einer Funktion basierend auf der Rolle eines Benutzers ein. Durch die Konsolidierung solcher Logik in einem Dekorator kann verhindert werden, dass die Berechtigungsverwaltungslogik über den gesamten Code verstreut ist, was die Lesbarkeit erhöht.

Verschachtelung von Dekoratoren

Es ist möglich, mehrere Dekoratoren anzuwenden. Wenn mehrere Dekoratoren auf eine einzelne Funktion angewandt werden, werden sie in der Reihenfolge von oben nach unten ausgeführt.

 1def uppercase(func):
 2    def wrapper(*args, **kwargs):
 3        result = func(*args, **kwargs)
 4        return result.upper()
 5    return wrapper
 6
 7def exclaim(func):
 8    def wrapper(*args, **kwargs):
 9        result = func(*args, **kwargs)
10        return result + "!"
11    return wrapper
12
13@uppercase
14@exclaim
15def greet(name):
16    return f"Hello, {name}"
17
18print(greet("Alice"))  # "HELLO, ALICE!"

In diesem Beispiel werden zwei Dekoratoren auf die Funktion greet angewandt. Der Dekorator @exclaim fügt am Ende des Strings ein Ausrufezeichen hinzu, und anschließend konvertiert @uppercase den String in Großbuchstaben.

Dekoratoren für Klassenmethoden

Dekoratoren können auch mit Klassenmethoden verwendet werden. Dies ist besonders nützlich, wenn das Verhalten von Methoden innerhalb einer Klasse gesteuert werden soll. Beim Anwenden von Dekoratoren auf Klassenmethoden sollte auf Argumente wie self oder cls geachtet werden.

 1def log_method_call(func):
 2    def wrapper(self, *args, **kwargs):
 3        print(f"Calling method '{func.__name__}'...")
 4        return func(self, *args, **kwargs)
 5    return wrapper
 6
 7class MyClass:
 8    @log_method_call
 9    def greet(self, name):
10        print(f"Hello, {name}")
11
12obj = MyClass()
13obj.greet("Bob")

In diesem Beispiel wird der Dekorator log_method_call auf die Methode greet angewandt, um ein Log auszugeben, wenn die Methode aufgerufen wird.

Vorsichtsmaßnahmen bei der Verwendung von Dekoratoren

Es gibt einige Überlegungen bei der Verwendung von Dekoratoren. Dekoratoren können möglicherweise den Namen und die Dokumentationszeichenkette der ursprünglichen Funktion (z. B. __name__ oder __doc__) ändern, daher wird empfohlen, functools.wraps zu verwenden, um diese Informationen beizubehalten.

1import functools
2
3def my_decorator(func):
4    @functools.wraps(func)
5    def wrapper(*args, **kwargs):
6        print("Before the function call")
7        return func(*args, **kwargs)
8    return wrapper

Die Verwendung von @functools.wraps stellt sicher, dass die Metadaten der ursprünglichen Funktion korrekt an die Wrapper-Funktion übergeben werden.

Zusammenfassung

Python-Dekoratoren sind ein sehr leistungsstarkes Werkzeug, mit dem Sie Funktionen und Methoden prägnant zusätzliche Funktionalitäten hinzufügen können. Sie können in verschiedenen Szenarien verwendet werden, um Code-Duplikation zu reduzieren und die Wartbarkeit sowie Wiederverwendbarkeit zu verbessern. Indem Sie verstehen, wie Dekoratoren funktionieren, können Sie effizienteren und flexibleren Code schreiben.

Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.

YouTube Video