Zephyrnet-Logo

8 integrierte Python-Dekoratoren zum Schreiben eleganten Codes – KDnuggets

Datum:

8 integrierte Python-Dekoratoren zum Schreiben eleganten Codes
Bild vom Herausgeber
 

Python ist mit seiner sauberen und lesbaren Syntax eine weit verbreitete Programmiersprache auf hohem Niveau. Python ist auf Benutzerfreundlichkeit ausgelegt, wobei Einfachheit und reduzierte Kosten für die Programmwartung im Vordergrund stehen. Es verfügt über eine umfangreiche Bibliothek, die es Entwicklern erspart, Code von Grund auf neu zu schreiben, und die Produktivität der Entwickler erhöht. Eine leistungsstarke Funktion von Python, die zur Eleganz des Codes beiträgt, sind Dekoratoren.

In Python ist ein Dekorator eine Funktion, mit der Sie das Verhalten einer anderen Funktion ändern können, ohne deren Kernlogik zu ändern. Es nimmt eine andere Funktion als Argument und gibt die Funktion mit erweiterter Funktionalität zurück. Auf diese Weise können Sie Dekoratoren verwenden, um vorhandenen Funktionen zusätzliche Logik hinzuzufügen und so die Wiederverwendbarkeit mit nur wenigen Codezeilen zu erhöhen. In diesem Artikel werden wir acht integrierte Python-Dekoratoren untersuchen, die Ihnen dabei helfen können, eleganteren und wartbareren Code zu schreiben.

 

8 integrierte Python-Dekoratoren zum Schreiben eleganten Codes
Bild vom Herausgeber

Das @atexit.register Der Dekorator wird verwendet, um eine Funktion zu registrieren, die bei Programmbeendigung ausgeführt werden soll. Diese Funktion kann verwendet werden, um jede Aufgabe auszuführen, wenn das Programm kurz vor dem Beenden steht, unabhängig davon, ob dies auf eine normale Ausführung oder einen unerwarteten Fehler zurückzuführen ist.

Beispiel:

import atexit

# Register the exit_handler function
@atexit.register
def exit_handler():
    print("Exiting the program. Cleanup tasks can be performed here.")

# Rest of the program
def main():
    print("Inside the main function.")
    # Your program logic goes here.

if __name__ == "__main__":
    main()

Ausgang:

Inside the main function.
Exiting the program. Cleanup tasks can be performed here.

 

In der obigen Implementierung @atexit.register wird oberhalb der Funktionsdefinition erwähnt. Es definiert die exit_handler() Funktion als Exit-Funktion. Im Wesentlichen bedeutet dies, dass jedes Mal, wenn das Programm seinen Endpunkt erreicht, sei es durch die normale Ausführung oder aufgrund eines unerwarteten Fehlers, der zu einem vorzeitigen Beenden führt, das exit_handler() Funktion wird aufgerufen.

Das @dataclasses.dataclass ist ein leistungsstarker Dekorator, der zum automatischen Generieren allgemeiner Spezialmethoden für Klassen wie „__init__“, „__repr__“ und andere verwendet wird. Es hilft Ihnen, saubereren und prägnanteren Code zu schreiben, da es nicht mehr erforderlich ist, Standardmethoden zum Initialisieren und Vergleichen von Instanzen Ihrer Klasse zu schreiben. Es kann auch dazu beitragen, Fehler zu vermeiden, indem sichergestellt wird, dass allgemeine Spezialmethoden in Ihrer Codebasis konsistent implementiert werden.

Beispiel:

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int


point = Point(x=3, y=2)
# Printing object
print(point)

# Checking for the equality of two objects
point1 = Point(x=1, y=2)
point2 = Point(x=1, y=2)
print(point1 == point2)

Ausgang:

Point(x=3, y=2)
True

 

Das @dataclass Der über der Point-Klassendefinition angewendete Decorator signalisiert Python, das Standardverhalten zum Generieren spezieller Methoden zu verwenden. Dadurch wird automatisch das erstellt __init__ Methode, die Klassenattribute wie x und y bei der Objektinstanziierung initialisiert. Dadurch können Instanzen wie point erstellt werden, ohne dass eine explizite Codierung erforderlich ist. Darüber hinaus ist die __repr__ Die Methode, die für die Bereitstellung einer Zeichenfolgendarstellung von Objekten verantwortlich ist, wird ebenfalls automatisch angepasst. Dadurch wird sichergestellt, dass beim Drucken eines Objekts, beispielsweise eines Punkts, eine klare und geordnete Darstellung entsteht, wie in der Ausgabe zu sehen ist: Point(x=3, y=2). Darüber hinaus ergibt der Gleichheitsvergleich (==) zwischen zwei Instanzen, Punkt1 und Punkt2, „True“. Dies ist bemerkenswert, da Python standardmäßig anhand des Speicherorts prüft, ob Gleichheit vorliegt. Im Kontext von Datenklassenobjekten wird die Gleichheit jedoch durch die darin enthaltenen Daten bestimmt. Dies liegt daran, dass der @dataclass-Dekorator eine generiert __eq__ Methode, die die Gleichheit der in den Objekten vorhandenen Daten prüft, anstatt nach demselben Speicherort zu suchen.

Das @enum.unique Der im Enum-Modul enthaltene Decorator wird verwendet, um sicherzustellen, dass die Werte aller Mitglieder einer Enumeration eindeutig sind. Dadurch wird verhindert, dass versehentlich mehrere Aufzählungsmitglieder mit demselben Wert erstellt werden, was zu Verwirrung und Fehlern führen kann. Wenn doppelte Werte gefunden werden, a WertFehler angehoben wird.

Beispiel:

from enum import Enum, unique

@unique
class VehicleType(Enum):
    CAR = 1
    TRUCK = 2
    MOTORCYCLE = 3
    BUS = 4

# Attempting to create an enumeration with a duplicate value will raise a ValueError
try:
    @unique
    class DuplicateVehicleType(Enum):
        CAR = 1
        TRUCK = 2
        MOTORCYCLE = 3
        # BUS and MOTORCYCLE have duplicate values
        BUS = 3
except ValueError as e:
    print(f"Error: {e}")

 

Ausgang:

Error: duplicate values found in : BUS -> MOTORCYCLE

 

In der obigen Implementierung haben „BUS“ und „MOTORRAD“ den gleichen Wert „3“. Infolgedessen ist die @unique Der Dekorator löst einen ValueError mit der Meldung aus, dass doppelte Werte gefunden wurden. Weder können Sie denselben Schlüssel mehr als einmal verwenden, noch können Sie verschiedenen Mitgliedern denselben Wert zuweisen. Auf diese Weise werden doppelte Werte für mehrere Aufzählungsmitglieder verhindert.

Das partial Decorator ist ein leistungsstarkes Werkzeug, mit dem Teilfunktionen erstellt werden. Mit Teilfunktionen können Sie einige der Argumente der ursprünglichen Funktion voreinstellen und eine neue Funktion mit diesen bereits ausgefüllten Argumenten generieren.

Beispiel:

from functools import partial

# Original function
def power(base, exponent):
    return base ** exponent

# Creating a partial function with the exponent fixed to 2
square = partial(power, exponent=2)

# Using the partial function
result = square(3)
print("Output:",result)

 

Ausgang:

 

In der obigen Implementierung haben wir eine Funktion „Potenz“, die zwei Argumente „Basis“ und „Exponent“ akzeptiert und das Ergebnis der mit dem Exponenten potenzierten Basis zurückgibt. Wir haben mit der Originalfunktion eine Teilfunktion namens „Quadrat“ erstellt, bei der der Exponent auf 2 voreingestellt ist. Auf diese Weise können wir die Funktionalität der Originalfunktionen mit a erweitern partial Dekorateur.

Das @singledisptach Der Dekorator wird zum Erstellen allgemeiner Funktionen verwendet. Sie können damit verschiedene Implementierungen von Funktionen mit demselben Namen, aber unterschiedlichen Argumenttypen definieren. Dies ist besonders nützlich, wenn Sie möchten, dass sich Ihr Code für verschiedene Datentypen unterschiedlich verhält.

Beispiel:

from functools import singledispatch

# Decorator
@singledispatch
def display_info(arg):
    print(f"Generic: {arg}")

# Registering specialized implementations for different types
@display_info.register(int)
def display_int(arg):
    print(f"Received an integer: {arg}")

@display_info.register(float)
def display_float(arg):
    print(f"Received a float: {arg}")

@display_info.register(str)
def display_str(arg):
    print(f"Received a string: {arg}")

@display_info.register(list)
def display_sequence(arg):
    print(f"Received a sequence: {arg}")

# Using the generic function with different types
display_info(39)             
display_info(3.19)          
display_info("Hello World!")
display_info([2, 4, 6])     

 

Ausgang:

Received an integer: 39
Received a float: 3.19
Received a string: Hello World!
Received a sequence: [2, 4, 6]

 

In der obigen Implementierung haben wir zunächst die generische Funktion entwickelt display_info() Verwendung der @singledisptach decorator und registrierte dann seine Implementierung für int, float, string und list separat. Die Ausgabe zeigt die Funktionsweise von display_info() für separate Datentypen.

Das @classmethod ist ein Dekorator, der zum Definieren von Klassenmethoden innerhalb der Klasse verwendet wird. Klassenmethoden sind an die Klasse und nicht an das Objekt der Klasse gebunden. Der Hauptunterschied zwischen statischen Methoden und Klassenmethoden liegt in ihrer Interaktion mit dem Klassenzustand. Klassenmethoden haben Zugriff auf den Klassenstatus und können ihn ändern, wohingegen statische Methoden nicht auf den Klassenstatus zugreifen und unabhängig arbeiten können.

Beispiel:

class Student:
    total_students = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Student.total_students += 1

    @classmethod
    def increment_total_students(cls):
        cls.total_students += 1
        print(f"Class method called. Total students now: {cls.total_students}")

# Creating instances of the class
student1 = Student(name="Tom", age=20)
student2 = Student(name="Cruise", age=22)

# Calling the class method
Student.increment_total_students()  #Total students now: 3

# Accessing the class variable
print(f"Total students from student 1: {student1.total_students}")
print(f"Total students from student 2: {student2.total_students}")

 

Ausgang:

Class method called. Total students now: 3
Total students from student 1: 3
Total students from student 2: 3

 

In der obigen Implementierung ist die Schüler und Studenten Klasse hat total_students als Klassenvariable. Der @classmethod Der Dekorator wird verwendet, um die zu definieren increment_total_students() Klassenmethode zum Erhöhen der total_students Variable. Immer wenn wir eine Instanz der Student-Klasse erstellen, wird die Gesamtzahl der Studenten um eins erhöht. Wir haben zwei Instanzen der Klasse erstellt und diese dann mit der Klassenmethode geändert total_students variabel zu 3, was sich auch in den Instanzen der Klasse widerspiegelt.

Das @staticmethod Decorator wird verwendet, um statische Methoden innerhalb einer Klasse zu definieren. Statische Methoden sind Methoden, die aufgerufen werden können, ohne eine Instanz der Klasse zu erstellen. Statische Methoden werden häufig verwendet, wenn sie nicht auf objektbezogene Parameter zugreifen müssen und sich eher auf die Klasse als Ganzes beziehen.

Beispiel:

class MathOperations:
    @staticmethod
    def add(x, y):
        return x + y

    @staticmethod
    def subtract(x, y):
        return x - y

# Using the static methods without creating an instance of the class
sum_result = MathOperations.add(5, 4)
difference_result = MathOperations.subtract(8, 3)

print("Sum:", sum_result)            
print("Difference:", difference_result)

 

Ausgang:

Sum: 9
Difference: 5

 

In der obigen Implementierung haben wir verwendet @staticmethod um eine statische Methode add() für die Klasse „MathOperations“ zu definieren. Wir haben die beiden Zahlen „4“ und „5“ hinzugefügt, was zu „9“ führt, ohne eine Instanz der Klasse zu erstellen. Subtrahieren Sie auf ähnliche Weise die beiden Zahlen „8“ und „3“, um „5“ zu erhalten. Auf diese Weise können statische Methoden generiert werden, um Hilfsfunktionen auszuführen, die nicht den Status einer Instanz erfordern. 

Das @property Mit dem Decorator werden die Getter-Methoden für das Klassenattribut definiert. Die Getter-Methoden sind die Methoden, die den Wert eines Attributs zurückgeben. Diese Methoden werden zur Datenkapselung verwendet, die angibt, wer auf die Details der Klasse oder Instanz zugreifen kann.

Beispiel:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        # Getter method for the radius.
        return self._radius

    @property
    def area(self):
        # Getter method for the area.
        return 3.14 * self._radius**2

# Creating an instance of the Circle class
my_circle = Circle(radius=5)

# Accessing properties using the @property decorator
print("Radius:", my_circle.radius)          
print("Area:", my_circle.area)  

 

Ausgang:

Radius: 5
Area: 78.5

 

In der obigen Implementierung hat die Klasse „Circle“ ein Attribut „radius“. Wir haben benutzt @property um die Getter-Methoden sowohl für den Radius als auch für die Fläche einzurichten. Es bietet den Benutzern der Klasse eine saubere und konsistente Schnittstelle für den Zugriff auf diese Attribute. 

In diesem Artikel werden einige der vielseitigsten und funktionalsten Dekoratoren vorgestellt, mit denen Sie Ihren Code flexibler und lesbarer machen können. Mit diesen Dekoratoren können Sie die Funktionalitäten der ursprünglichen Funktion erweitern, um sie besser zu organisieren und weniger fehleranfällig zu machen. Sie sind wie magische Handgriffe, die dafür sorgen, dass Ihre Python-Programme ordentlich aussehen und reibungslos funktionieren.
 
 

Kanwal Mehreen ist ein aufstrebender Softwareentwickler mit großem Interesse an Data Science und Anwendungen von KI in der Medizin. Kanwal wurde als Google Generation Scholar 2022 für die APAC-Region ausgewählt. Kanwal liebt es, technisches Wissen zu teilen, indem sie Artikel zu Trendthemen schreibt, und setzt sich leidenschaftlich für die Verbesserung der Vertretung von Frauen in der Technologiebranche ein.

spot_img

Neueste Intelligenz

spot_img