Dataclass in Python¶
Fortgeschrittene Techniken mit Python dataclass¶

In diesem Kapitel unseres Python-Tutorials tauchen wir in die mächtige Welt der Python-Datenklassen ein. Datenklassen sind ein wesentliches Feature, was in Python 3.7 eingeführt wurde, um die Erstellung und Verwaltung von Klassen zu vereinfachen, die hauptsächlich zum Speichern von Daten verwendet werden. Zu Beginn des Kapitels werden die Unterschiede zwischen traditionellen Klassenstrukturen zur Darstellung von Daten aufgezeigt und Dataclasses als attraktive Alternative vorgestellt. Wir werden die Syntax und die Funktionalitäten von Datenklassen untersuchen und zeigen, wie die Lesbarkeit des Codes durch sie verbessert werden kann.
Erste Beispiele¶
In unserem ersten Beispiel bleiben wir unserem geliebten Roboter Marvin treu. Wir beginnen also mit einer "traditionellen" Python-Klasse Robot_traditional, die einen Roboter darstellt:
class Robot_traditional:
    
    def __init__(self, model, serial_number, manufacturer):
        self.model = model
        self.serial_number = serial_number
        self.manufacturer = manufacturer
Der Standardcode innerhalb der __init__-Methode folgt einem ähnlichen Musterin fast allen Klassendefinition. So auch indiesem Beispiel, wobei die einzige Variation die Namen der den Attributen zugewiesenen Bezeichnungen sind. Dies wird besonders mühsam, wenn die Anzahl der Attribute zunimmt.
Wenn wir uns das gleiche Beispiel in der Notation mittels dataclass anschauen, sehen wir, dass der Code erheblich schlanker wird. Bevor wir jedoch dataclass als Dekorateur für unsere Klasse verwenden können, müssen wir es aus dem Modul dataclasses importieren.
from dataclasses import dataclass
@dataclass
class Robot:
    model: str
    serial_number: str
    manufacturer: str
Hier automatisiert der Datenklassen-Dekorator die Generierung spezieller Methoden wie __init__, wodurch der Bedarf an Boilerplate-Code reduziert wird. Die Klassendefinition ist prägnant, was sie übersichtlicher und wartungsfreundlicher macht, insbesondere wenn die Anzahl der Attribute steigt.
Dieses Beispiel zeigt, wie die Verwendung von Datenklassen für eine Klasse, die hauptsächlich zum Speichern von Daten verwendet wird, wie z. B. eine Roboterdarstellung, eine schlankere und lesbarere Alternative zu traditionellen Klassenstrukturen bietet.
Die Initialisierung von Robotern beider Klassen ist identisch;
x = Robot_traditional("NanoGuardian XR-2000", "234-76", "Cyber Robotics Co.")
y = Robot("MachinaMaster MM-42", "986-42", "Quantum Automations Inc.")
Doch es gibt noch weitere Unterschiede in diesen Klassen. Der Klassendekorator dataclass hat nicht nur die spezielle Methode __init__ erstellt, sondern auch __repr__, __eq__, __ne__ und __hash__. Methoden, die Sie ansonsten manuell zum Aufruf Robot_traditional hinzufügen müssten.
Werfen wir einen Blick auf __repr__ und vergleichen wir es mit der traditionellen Klassendefinition:
class Robot_traditional:
    
    def __init__(self, model, serial_number, manufacturer):
        self.model = model
        self.serial_number = serial_number
        self.manufacturer = manufacturer
    def __repr__(self):
        return f"Robot_traditional(model='{self.model}', serial_number='{self.serial_number}', manufacturer='{self.manufacturer}')"
x = Robot_traditional("NanoGuardian XR-2000", "234-76", "Cyber Robotics Co.")
print(repr(x))
Unveränderliche Klassen¶
In unserem Kapitel zu Unveränderliche Klassen in Python (Immutable Klassen unseres Tutorials diskutieren wir die Gründe für die Notwendigkeit von Unveränderlichkeit und erkunden verschiedene Methoden zu ihrer Erstellung.
Mit Dataclasses ist es sehr einfach. Alles, was man tun muss, ist, den Dekorator mit frozen=True aufzurufen:
from dataclasses import dataclass
@dataclass(frozen=True)
class ImmutableRobot:
    name: str
    brandname: str
Mit dieser Klasse können wir zwei Roboter auf Gleichheit prüfen. Sie sind gleich, wenn alle Attribute gleich sind. Denken Sie daran, dass __eq__ automatisch erstellt wurde.
x1 = ImmutableRobot("Marvin", "NanoGuardian XR-2000")
x2 = ImmutableRobot("Marvin", "NanoGuardian XR-2000")
print(x1 == x2)
Schauen wir uns die Hahs-Werte an:
print(x1.__hash__(), x2.__hash__())
Zunächst können wir sehen, dass __hash__ automatisch erstellt und korrekt implementiert wurde.  Dadurch wird sichergestellt, dass Roboter, die gleich sind, identische Hash-Werte erzeugen.
Nun wollen wir eine ähnliche Klasse implementieren, ohne eine Datenklasse zu verwenden. In unserer zuvor definierten Klasse Robot_traditional sind die Instanzen veränderbar, da wir die Möglichkeit haben, die Attribute zu ändern. Das folgende Beispiel ist eine unveränderliche Version. Wir können sofort sehen, dass es eine Menge mehr Kodierungsaufwand gibt. Wir müssen __init__', die Getter-Eigenschaften,equndhash` implementieren:
class ImmutableRobot_traditional:
    
    def __init__(self, name: str, brandname: str):
        self._name = name
        self._brandname = brandname
    @property
    def name(self) -> str:
        return self._name
    @property
    def brandname(self) -> str:
        return self._brandname
    def __eq__(self, other):
        if not isinstance(other, ImmutableRobot_traditional):
            return False
        return self.name == other.name and self.brandname == other.brandname
    def __hash__(self):
        return hash((self.name, self.brandname))
x1 = ImmutableRobot_traditional("Marvin", "NanoGuardian XR-2000")
x2 = ImmutableRobot_traditional("Marvin", "NanoGuardian XR-2000")
print(x1 == x2)
print(x1.__hash__(), x2.__hash__())
print(x1.__hash__(), x2.__hash__())
Eine unveränderliche Klasse mit einer `hash-Methode zu haben, bedeutet, dass wir unsere Klasse in Mengen und Wörterbüchern verwenden können. Wir veranschaulichen dies im folgenden Beispiel:
from dataclasses import dataclass
@dataclass(frozen=True)
class ImmutableRobot:
    name: str
    brandname: str
robot1 = ImmutableRobot("Marvin", "NanoGuardian XR-2000")
robot2 = ImmutableRobot("R2D2", "QuantumTech Sentinel-7")
robot3 = ImmutableRobot("Marva", "MachinaMaster MM-42")
# we create a set of Robots:
robots = {robot1, robot2, robot3}
print("The robots in the set robots:")
for robo in robots:
    print(robo)
# now a dictionary with robots as keys:
activity = {robot1: 'activated', robot2: 'activated', robot3: 'deactivated'}
print("\nAll the activated robots:")
for robo, mode in activity.items():
    if mode == 'activated':
        print(f"{robo} is activated")
Zusammenfassung¶
Die Verwendung einer Datenklasse bietet mehrere Vorteile gegenüber traditionellen Klassendefinitionen in Python:
- Automatische Generierung von speziellen Methoden: Mit Datenklassen müssen Sie spezielle Methoden wie - __init__,- __repr__,- __eq__,- __hash__usw. nicht manuell schreiben. Der- dataclass-Dekorator generiert diese Methoden automatisch basierend auf den Klassenattributen, die Sie definieren.
- Prägnante Syntax: - dataclassverwendet eine prägnante Syntax zur Definition von Klassen, wodurch Boilerplate-Code reduziert wird. Sie müssen nur die Attribute der Klasse angeben, und der Dekorator kümmert sich um den Rest.
- Integrierte Vergleichsmethoden: - dataclassbietet automatisch Implementierungen für Vergleichsmethoden wie- __eq__,- __ne__,- __lt__,- __le__,- __gt__und- __ge__, basierend auf den Attributen der Klasse.
- Unveränderliche Instanzen: Durch die Angabe von - frozen=Trueim- dataclass-Dekorator können Instanzen der Klasse unveränderlich gemacht werden, was dazu beitragen kann, versehentliche Änderungen an Daten zu verhindern.
- Integration mit Typ-Hinweisen: - dataclassintegriert sich nahtlos in das Typ-Hinweis-System von Python, sodass Sie die Typen von Attributen für eine bessere Code-Lesbarkeit und statische Analyse angeben können.
- Standardwerte und Standardwerte-Fabrik: Sie können Standardwerte für Attribute direkt in der Klassendefinition oder unter Verwendung von Fabrikfunktionen angeben, was die Notwendigkeit für Boilerplate-Code in der - __init__-Methode reduziert.
- Unterstützung für Vererbung: - dataclassunterstützt Vererbung, sodass Sie Unterklassen mit zusätzlichen Attributen oder Methoden erstellen können, während Sie das Verhalten der Elternklasse erben.
- Anpassung: Obwohl - dataclassdie automatische Generierung spezieller Methoden bietet, können Sie diese Methoden bei Bedarf weiterhin anpassen oder überschreiben, was Ihnen Flexibilität bei der Definition des Klassenverhaltens gibt.
Insgesamt vereinfacht dataclass den Prozess der Klassenerstellung in Python und macht den Code prägnanter, lesbarer und wartbarer, insbesondere für Klassen, die hauptsächlich als Container für Daten dienen.
This Markdown text provides the translated version of the original text into German.
Exercises¶
Exercise 1: Buchinformationen¶
Erstellen Sie eine Book-Klasse mithilfe von dataclass, um Informationen über Bücher darzustellen. Jedes Buch sollte die folgenden Attribute haben:
- Titel
- Autor
- ISBN (Internationale Standardbuchnummer)
- Veröffentlichungsjahr
- Genre
Schreiben Sie ein Programm, das Folgendes tut:
- Definieren Sie die Book-Klasse mitdataclass.
- Erstellen Sie Instanzen mehrerer Bücher.
- Geben Sie die Details jedes Buches aus, einschließlich Titel, Autor, ISBN, Veröffentlichungsjahr und Genre.
Sie können diese Übung verwenden, um das Definieren von dataclass, das Erstellen von Instanzen und den Zugriff auf Attribute von dataclass-Objekten zu üben. Darüber hinaus können Sie erkunden, wie Sie der Book-Klasse Methoden oder Anpassungen hinzufügen können, z. B. eine Methode zur Berechnung des Alters des Buches basierend auf dem Veröffentlichungsjahr oder die Validierung von ISBN-Nummern hinzufügen.
from dataclasses import dataclass
@dataclass
class Book:
    title: str
    author: str
    isbn: str
    publication_year: int
    genre: str
# Create instances of several books
buch1 = Book("Die Verwandlung", "Franz Kafka", "9783150091563", 1915, "Roman")
buch2 = Book("Faust. Der Tragödie erster Teil", "Johann Wolfgang von Goethe", "9783150000008", 1808, "Drama")
buch3 = Book("Der Steppenwolf", "Hermann Hesse", "9783518366868", 1927, "Roman")
# Print out the details of each book
print("Buch 1:")
print("Titel:", buch1.title)
print("Autor:", buch1.author)
print("ISBN:", buch1.isbn)
print("Veröffentlichungsjahr:", buch1.publication_year)
print("Genre:", buch1.genre)
print("\nBuch 2:")
print("Titel:", buch2.title)
print("Autor:", buch2.author)
print("ISBN:", buch2.isbn)
print("Veröffentlichungsjahr:", buch2.publication_year)
print("Genre:", buch2.genre)
print("\nBuch 3:")
print("Titel:", buch3.title)
print("Autor:", buch3.author)
print("ISBN:", buch3.isbn)
print("Veröffentlichungsjahr:", buch3.publication_year)
print("Genre:", buch3.genre)

 
 Buch kaufen
Buch kaufen
 Buch kaufen
Buch kaufen
 Buch kaufen
Buch kaufen

