Geekflare wird von unserem Publikum unterstützt. Es kann sein, dass wir durch den Kauf von Links auf dieser Seite Affiliate-Provisionen verdienen.
Unter Entwicklung Zuletzt aktualisiert: September 24, 2023
Weitergeben:
Invicti Web Application Security Scanner - die einzige Lösung, die eine automatische Überprüfung von Schwachstellen mit Proof-Based Scanning™ ermöglicht.

Python-Dekoratoren sind ein unglaublich nützliches Konstrukt in Python. Mit Dekoratoren in Python können wir das Verhalten einer Funktion ändern, indem wir sie in eine andere Funktion einpacken. Mit Dekoratoren können wir sauberen Code schreiben und Funktionen gemeinsam nutzen. In diesem Artikel lernen Sie nicht nur, wie man Dekoratoren verwendet, sondern auch, wie man sie erstellt.

Vorausgesetztes Wissen

Das Thema Dekoratoren in Python erfordert etwas Hintergrundwissen. In der Folge habe ich einige Konzepte aufgeführt, mit denen Sie bereits vertraut sein sollten, um dieses Tutorial sinnvoll zu nutzen. Ich habe auch Ressourcen verlinkt, in denen Sie die Konzepte bei Bedarf auffrischen können.

Grundlagen von Python

Dieses Thema ist ein Thema für Fortgeschrittene. Daher sollten Sie bereits mit den Grundlagen von Python vertraut sein, z.B. mit Datentypen, Funktionen, Objekten und Klassen, bevor Sie versuchen, es zu lernen.

Sie sollten auch einige objektorientierte Konzepte wie Getter, Setter und Konstruktoren verstehen. Wenn Sie mit der Programmiersprache Python nicht vertraut sind, finden Sie hier einige Ressourcen, die Ihnen den Einstieg erleichtern erleichtern.

Funktionen sind Bürger erster Klasse

Zusätzlich zu den Grundkenntnissen in Python sollten Sie auch dieses fortgeschrittenere Konzept in Python kennen. Funktionen, und so ziemlich alles andere in Python, sind Objekte wie int oder string. Da es sich um Objekte handelt, können Sie einige Dinge mit ihnen tun, und zwar:

  • Sie können eine Funktion als Argument an eine andere Funktion übergeben, genauso wie Sie eine String oder int als Funktionsargument übergeben.
  • Funktionen können auch von anderen Funktionen zurückgegeben werden, so wie Sie andere String- oder int-Werte zurückgeben würden.
  • Funktionen können in Variablen gespeichert werden

Tatsächlich besteht der einzige Unterschied zwischen funktionalen Objekten und anderen Objekten darin, dass funktionale Objekte die magische Methode __call__() enthalten.

Wir hoffen, dass Sie an dieser Stelle mit dem vorausgesetzten Wissen vertraut sind. Wir können mit der Diskussion des Hauptthemas beginnen.

Was ist ein Python-Dekorator?

Ein Python-Dekorator ist einfach eine Funktion, die eine Funktion als Argument entgegennimmt und eine modifizierte Version der übergebenen Funktion zurückgibt. Mit anderen Worten: Die Funktion foo ist ein Dekorator, wenn sie als Argument die Funktion bar entgegengenommen und eine andere Funktion baz zurückgibt.

Die Funktion baz ist eine Modifikation von bar in dem Sinne, dass im Körper von baz ein Aufruf der Funktion bar erfolgt. Vor und nach dem Aufruf von bar kann baz jedoch alles tun. Das war ein ganz schöner Brocken; hier ist etwas Code, um die Situation zu veranschaulichen:

# Foo ist ein Dekorator, er nimmt eine andere Funktion, bar, als Argument auf
def foo(bar):

   # Hier erzeugen wir baz, eine modifizierte Version von bar
 # baz ruft bar auf, kann aber vor und nach dem Funktionsaufruf alles tun
 def baz():

       # Bevor wir bar aufrufen, drucken wir etwas
 print("Etwas")

 # Dann führen wir bar aus, indem wir einen Funktionsaufruf machen
 bar()

 # Dann drucken wir etwas anderes, nachdem wir bar ausgeführt haben
 print("Etwas anderes")

 # Schließlich gibt foo baz zurück, eine modifizierte Version von bar
 return baz

Wie erstellt man einen Dekorator in Python?

Um zu veranschaulichen, wie Dekoratoren in Python erstellt und verwendet werden, werde ich dies anhand eines einfachen Beispiels erläutern. In diesem Beispiel werden wir eine Logger-Dekoratorfunktion erstellen, die den Namen der Funktion, die sie dekoriert, jedes Mal protokolliert, wenn diese Funktion ausgeführt wird.

Um zu beginnen, haben wir die Dekorator-Funktion erstellt. Der Dekorator nimmt func als Argument dagegen. func ist die Funktion, die wir dekorieren.

def create_logger(func):
   # Der Funktionskörper kommt hier hin

Innerhalb der Decorator-Funktion erstellen wir unsere modifizierte Funktion, die den Namen von func protokolliert, bevor wir func ausführen.

# Innerhalb von create_logger
def modified_func():
 print("Aufruf: ", func.__name__)
 func()

Anschließend gibt es die Funktion create_logger die geänderte Funktion zurück. Unsere gesamte Funktion create_logger sieht dann wie folgt aus:

def create_logger(func):
 def modified_func():
 print("Calling: ", func.__name__)
 func()

 return modified_function

Wir sind mit der Erstellung des Dekorators fertig. Die Funktion create_logger ist ein einfaches Beispiel für eine Decorator-Funktion. Sie nimmt func auf, die Funktion, die wir dekorieren, und gibt eine andere Funktion, modified_func, zurück. modified_func protokolliert zunächst den Namen von func, bevor func ausgeführt wird.

Wie man Dekoratoren in Python verwendet

Um unseren Dekorator zu verwenden, benutzen wir die @-Syntax wie folgt:

@create_logger
def say_hello():
 print("Hallo, Welt!")

Jetzt können wir say_hello() in unserem Skript aufrufen, und die Ausgabe sollte folgendermaßen aussehen:

Aufruf von: say_hello
"Hallo, Welt"
Screenshot eines Programms, das Python-Dekoratoren verwendet

Aber was macht der @create_logger? Nun, er wendet den Dekorator auf unsere say_hello-Funktion an. Um besser zu verstehen, was er tut, würde der Code direkt unter diesem Absatz das gleiche Ergebnis erzielen, wenn Sie @create_logger vor say_hello einfügen.

def say_hello():
 print("Hallo, Welt!")

say_hello = create_logger(say_hello)

Mit anderen Worten: Eine Möglichkeit, Dekoratoren in Python zu verwenden, besteht darin, den Dekorator explizit aufzurufen und die Funktion zu übergeben, wie wir es im obigen Code getan haben. Der andere und prägnantere Weg ist die Verwendung der @-Syntax.

In diesem Abschnitt haben wir behandelt, wie man Python-Dekoratoren erstellt.

Etwas kompliziertere Beispiele

Das obige Beispiel war ein einfacher Fall. Es gibt etwas komplexere Beispiele, z.B. wenn die Funktion, die wir dekorieren, Argumente enthält. Eine andere, kompliziertere Situation ist, wenn Sie eine ganze Klasse dekorieren möchten. Ich werde diese beiden Situationen hier behandeln.

Wenn die Funktion Argumente enthält

Wenn die Funktion, die Sie dekorieren, Argumente enthält, sollte die geänderte Funktion die Argumente erhalten und sie weitergeben, wenn sie schließlich die unveränderte Funktion aufruft. Wenn sich das verwirrend anhört, lassen Sie es mich mit den Worten von foo erklären.

Erinnern Sie sich daran, dass foo die Dekorfunktion ist, bar ist die Funktion, die wir dekorieren und baz ist die dekorierte bar. In diesem Fall nimmt bar die Argumente auf und gibt sie an baz während des Aufrufs von baz. Hier ist ein Codebeispiel, um das Konzept zu verdeutlichen:

def foo(bar):
 def baz(*args, **kwargs):
       # Sie können hier etwas tun
 ___
 # Dann machen wir den Aufruf von bar und übergeben args und kwargs
 bar(*args, **kwargs)
 # Sie können hier auch etwas tun
 ___

 return baz

Falls Sie *args und **kwargs ungewohnt vorkommen, handelt es sich dabei einfach um Zeiger auf die Positions- bzw. Schlüsselwortargumente.

Es ist wichtig zu wissen, dass baz Zugriff auf die Argumente hat und daher vor dem Aufruf von bar eine Überprüfung der Argumente durchführen kann.

Ein Beispiel wäre eine Dekorator-Funktion, ensure_stringdie sicherstellt, dass das Argument, das an eine Funktion übergeben wird, die sie dekoriert, eine Zeichenkette ist; wir würden sie wie folgt implementieren

def ensure_string(func):
 def decorated_func(text):
 if type(text) is not str:
            raise TypeError('argument to ' func.__name__ ' must be a string.')
 else:
 func(text)

 return decorated_func

Wir könnten die Funktion say_hello wie folgt dekorieren:

@ensure_string
def say_hello(name):
 print('Hallo', name)

Dann könnten wir den Code wie folgt testen:

say_hello('John') # Sollte problemlos laufen
say_hello(3) # Sollte eine Ausnahme auslösen

Und es sollte die folgende Ausgabe erzeugen:

Hallo John
Traceback (letzter Aufruf):
  File "/home/anesu/Documents/python-tutorial/./decorators.py", line 20, in <module> say hello(3) # should throw an exception
 File "/home/anesu/Documents/python-tu$ ./decorators.pytorial/./decorators.py", line 7, in decorated_func raise TypeError('argument to func._name_ must be a string.')
TypeError: argument to say hello must be a string. $0
Screenshot-from-2023-05-23-02-33-18

Wie erwartet, konnte das Skript 'Hallo John' ausgeben, da 'John' eine Zeichenkette ist. Beim Versuch, 'Hallo 3' zu drucken, wurde eine Ausnahme ausgelöst, da '3' keine Zeichenkette war. Der Dekorator ensure_string kann verwendet werden, um die Argumente jeder Funktion, die einen String benötigt, zu überprüfen.

Eine Klasse dekorieren

Neben der Dekoration von Funktionen können wir auch Klassen dekorieren. Wenn Sie einer Klasse einen Dekorator hinzufügen, ersetzt die dekorierte Methode die Konstruktor/Initiator-Methode (__init__) der Klasse.

Nehmen wir an, foo ist unser Dekorator und Bar ist die Klasse, die wir dekorieren, dann wird foo Bar.__init__ dekorieren. Dies ist nützlich, wenn wir etwas tun wollen, bevor Objekte vom Typ Bar instanziiert werden.

Das bedeutet, dass der folgende Code

def foo(func):
 def new_func(*args, **kwargs):
 print('Etwas vor der Instanziierung tun')
 func(*args, **kwargs)

 return new_func

@foo
class Bar:
 def __init__(self):
 print("Im Initiator")

Ist äquivalent zu

def foo(func):
 def new_func(*args, **kwargs):
 print('Einige Dinge vor der Instanziierung tun')
 func(*args, **kwargs)

 return new_func

class Bar:
 def __init__(self):
 print("Im Initiator")


Bar.__init__ = foo(Bar.__init__)

Wenn Sie ein Objekt der Klasse Bar instanziieren, das mit einer der beiden Methoden definiert wurde, sollten Sie die gleiche Ausgabe erhalten:

Einige Dinge vor der Instanziierung tun
In initiator
Screenshot-from-2023-05-23-02-20-38

Beispiele für Dekoratoren in Python

Sie können zwar Ihre eigenen Dekoratoren definieren, aber es gibt auch einige, die bereits in Python eingebaut sind. Hier sind einige der üblichen Dekoratoren, denen Sie in Python begegnen können:

@staticmethod

Die statische Methode wird in einer Klasse verwendet, um anzuzeigen, dass die Methode, die sie dekoriert, eine statische Methode ist. Statische Methoden sind Methoden, die ausgeführt werden können, ohne dass die Klasse instanziert werden muss. Im folgenden Codebeispiel erstellen wir eine Klasse Dog mit einer statischen Methode bark.

class Hund:
   @staticmethod
 def bark():
 print('Wuff, wuff!')

Jetzt kann die Methode bellen wie folgt aufgerufen werden:

Hund.bellen()

Wenn Sie den Code ausführen, erhalten Sie die folgende Ausgabe:

Wuff, wuff!
Screenshot-from-2023-05-23-02-02-07

Wie ich bereits im Abschnitt über die Verwendung von Dekoratoren erwähnt habe, können Dekoratoren auf zwei Arten verwendet werden. Die @-Syntax ist die prägnantere der beiden Möglichkeiten. Die andere Methode besteht darin, die Decorator-Funktion aufzurufen und dabei die Funktion, die wir dekorieren möchten, als Argument zu übergeben. Das bedeutet, dass der obige Code das Gleiche erreicht wie der folgende Code:

class Dog:
 def bark():
 print('Wuff, wuff!')

Dog.bark = staticmethod(Dog.bark)

Und wir können die Methode bellen immer noch auf die gleiche Weise verwenden

Hund.bellen()

Und es würde die gleiche Ausgabe erzeugen

Wuff, wuff!
Screenshot-from-2023-05-23-02-02-07-1

Wie Sie sehen, ist die erste Methode sauberer und es ist offensichtlicher, dass es sich um eine statische Funktion handelt, bevor Sie überhaupt angefangen haben, den Code zu lesen. Aus diesem Grund werde ich für die verbleibenden Beispiele die erste Methode verwenden. Aber vergessen Sie nicht, dass die zweite Methode eine Alternative ist.

@classmethod

Dieser Dekorator wird verwendet, um anzuzeigen, dass die Methode, die er dekoriert, eine Klassenmethode ist. Klassenmethoden sind statischen Methoden insofern ähnlich, als dass sie beide nicht erfordern, dass die Klasse instanziiert wird, bevor sie aufgerufen werden können.

Der Hauptunterschied besteht jedoch darin, dass Klassenmethoden Zugriff auf Klassenattribute haben, während statische Methoden dies nicht können. Das liegt daran, dass Python die Klasse automatisch als erstes Argument an eine Klassenmethode übergibt, wenn diese aufgerufen wird. Um eine Klassenmethode in Python zu erstellen, können wir den Dekorator classmethod verwenden.

class Hund:
   @classmethod
 def what_are_you(cls):
 print("Ich bin ein " cls.__name__ "!")

Um den Code auszuführen, rufen wir einfach die Methode auf, ohne die Klasse zu instanziieren:

Dog.what_are_you()

Und die Ausgabe ist:

Ich bin ein Hund!
Screenshot-from-2023-05-23-02-07-18

@Eigenschaft

Der Eigenschaftsdekorator wird verwendet, um eine Methode als Eigenschaftssetzer zu kennzeichnen. Kehren wir zu unserem Beispiel Hund zurück und erstellen wir eine Methode, die den Namen des Hundes abruft.

klasse Hund:
   # Erstellen einer Konstruktormethode, die den Namen des Hundes aufnimmt
 def __init__(self, name):

        # Erstellen einer privaten Eigenschaft name
 # Die doppelten Unterstriche machen das Attribut privat
 self.__name = name

    
 @property
 def name(self):
 return self.__name

Jetzt können wir auf den Namen des Hundes wie auf eine normale Eigenschaft zugreifen,

# Erstellen einer Instanz der Klasse
foo = Hund('foo')

# Zugriff auf die Eigenschaft name
print("Der Name des Hundes ist:", foo.name)

Und das Ergebnis der Ausführung des Codes wäre

Der Name des Hundes ist: foo
Screenshot-from-2023-05-23-02-09-42

@property.setter

Der Dekorator property.setter wird verwendet, um eine Setter-Methode für unsere Eigenschaften zu erstellen. Um den @property.setter-Dekorator zu verwenden, ersetzen Sie property durch den Namen der Eigenschaft, für die Sie einen Setter erstellen möchten. Wenn Sie zum Beispiel einen Setter für die Methode der Eigenschaft foo erstellen, lautet Ihr Dekorator @foo.setter. Zur Veranschaulichung hier ein Beispiel für Dog:

class Dog:
   # Erstellen einer Konstruktormethode, die den Namen des Hundes aufnimmt
 def __init__(self, name):

        # Erstellen einer privaten Eigenschaft name
 # Die doppelten Unterstriche machen das Attribut privat
 self.__name = name

    
 @property
 def name(self):
 return self.__name

 # Erstellen eines Setters für unsere Eigenschaft name
 @name.setter
 def name(self, new_name):
 self.__name = new_name

Um den Setter zu testen, können wir den folgenden Code verwenden:

# Erstellen eines neuen Hundes
foo = Dog('foo')

# Ändern des Hundenamens
foo.name = 'bar'

# Drucken des Hundenamens auf dem Bildschirm
print("Der neue Name des Hundes ist:", foo.name)

Wenn Sie den Code ausführen, erhalten Sie die folgende Ausgabe:

Der neue Name des Hundes ist: bar
Screenshot-from-2023-05-23-11-46-25

Die Bedeutung von Dekoratoren in Python

Nachdem wir nun erklärt haben, was Dekoratoren sind, und Sie einige Beispiele für Dekoratoren gesehen haben, können wir nun erörtern, warum Dekoratoren in Python wichtig sind. Dekoratoren sind aus mehreren Gründen wichtig. Einige davon habe ich im Folgenden aufgeführt:

  • Sie ermöglichen die Wiederverwendbarkeit von Code: In dem oben genannten Beispiel für die Protokollierung könnten wir den @create_logger für jede beliebige Funktion verwenden. Auf diese Weise können wir allen unseren Funktionen Protokollierungsfunktionen hinzufügen, ohne sie manuell für jede Funktion schreiben zu müssen.
  • Sie ermöglichen es Ihnen, modularen Code zu schreiben: Um noch einmal auf das Beispiel der Protokollierung zurückzukommen: Mit Dekoratoren können Sie die Kernfunktion, in diesem Fall say_hellovon den anderen benötigten Funktionen, in diesem Fall der Protokollierung, trennen.
  • Sie verbessern Frameworks und Bibliotheken: Dekoratoren werden in Python-Frameworks und -Bibliotheken ausgiebig verwendet, um zusätzliche Funktionen bereitzustellen. In Web-Frameworks wie Flask oder Django werden Dekoratoren zum Beispiel für die Definition von Routen, die Handhabung von Authentifizierung oder die Anwendung von Middleware auf bestimmte Ansichten verwendet.

Letzte Worte

Dekoratoren sind unglaublich nützlich. Sie können mit ihnen Funktionen erweitern, ohne deren Funktionalität zu verändern. Dies ist nützlich, wenn Sie die Leistung von Funktionen überwachen, protokollieren möchten, wann eine Funktion aufgerufen wird, Argumente vor dem Aufruf einer Funktion validieren oder Berechtigungen überprüfen möchten, bevor eine Funktion ausgeführt wird. Sobald Sie Dekoratoren verstehen, werden Sie in der Lage sein, Code auf sauberere Weise zu schreiben.

Als nächstes sollten Sie unsere Artikel über Tupel und die Verwendung von cURL in Python lesen.

  • Anesu Kafesu
    Autor
    Full-Stack-Webentwickler und technischer Redakteur. Lernt derzeit KI.
Dank an unsere Sponsoren
Weitere gute Lektüre zum Thema Entwicklung
Energie für Ihr Unternehmen
Einige der Tools und Dienste, die Ihr Unternehmen beim Wachstum unterstützen.
  • Invicti nutzt das Proof-Based Scanning™, um die identifizierten Schwachstellen automatisch zu überprüfen und innerhalb weniger Stunden verwertbare Ergebnisse zu erzielen.
    Versuchen Sie Invicti
  • Web Scraping, Residential Proxy, Proxy Manager, Web Unlocker, Search Engine Crawler und alles, was Sie zum Sammeln von Webdaten benötigen.
    Versuchen Sie Brightdata
  • Monday.com ist ein All-in-One-Betriebssystem, mit dem Sie Projekte, Aufgaben, Arbeit, Vertrieb, CRM, Arbeitsabläufe und vieles mehr verwalten können.
    Versuch Montag
  • Intruder ist ein Online-Schwachstellen-Scanner, der Schwachstellen in Ihrer Infrastruktur aufspürt, um kostspielige Datenschutzverletzungen zu vermeiden.
    Versuchen Sie Intruder