Zum Inhalt springen
JAY IMDAHL
App-Entwicklung 4 min

Python-Dekoratoren einfach erklärt

Dekoratoren gehören zu den beliebtesten Sprachfeatures der Programmiersprache Python. Lerne, eigene Dekoratorenzu erstellen, um Boilerplate-Code zu reduzieren.

Thumbnail mit Text "Dekoratoren einfach erklärt"
VIDEO · BINÄRVERKEHR
video-pendant zum tutorial auf dem binärverkehr-kanal

1. Das Problem: Boilerplate-Hölle

Wir wollen ein Haustier in Python abbilden — mit Name, Tierart und Alter. Das klingt einfach, aber eine saubere Klasse braucht überraschend viel Code.

Zunächst: Warum braucht man überhaupt diese ganzen Dunder-Methoden (__init__, __repr__, __eq__)?

  • __init__ — der Konstruktor. Ohne ihn kann man kein Haustier("Balu", "Hund", 3) schreiben.
  • __repr__ — bestimmt, was print(balu) ausgibt. Ohne diese Methode sieht man nur etwas Kryptisches wie <__main__.Haustier object at 0x7f3b2c> — das hilft niemandem beim Debuggen.
  • __eq__ — bestimmt, was bei == passiert. Ohne diese Methode vergleicht Python nur, ob es dasselbe Objekt im Speicher ist, nicht ob die Werte gleich sind:
balu1 = Haustier("Balu", "Hund", 3)
balu2 = Haustier("Balu", "Hund", 3)
print(balu1 == balu2)  # False! Gleiche Daten, aber zwei verschiedene Objekte

Um all das korrekt zu haben, muss man Folgendes schreiben:

class Haustier:
    def __init__(self, name: str, tierart: str, alter: int):
        self.name = name
        self.tierart = tierart
        self.alter = alter

    def __repr__(self):
        return f"Haustier(name='{self.name}', tierart='{self.tierart}', alter={self.alter})"

    def __eq__(self, other):
        if not isinstance(other, Haustier):
            return NotImplemented
        return (self.name == other.name
                and self.tierart == other.tierart
                and self.alter == other.alter)

Das sind 15 Zeilen — für drei Attribute. Und jedes Mal, wenn ein neues Attribut dazukommt (z. B. farbe), muss man an drei Stellen ändern: __init__, __repr__ und __eq__.

Können wir Python sagen: “Mach das für mich”?

2. Die Idee: Funktionen verändern Funktionen

In Python sind Funktionen Objekte. Man kann sie in Variablen speichern, an andere Funktionen übergeben und aus Funktionen zurückgeben. Das ermöglicht ein mächtiges Konzept: Dekoratoren.

Ein Dekorator ist eine Funktion, die eine andere Funktion entgegennimmt, sie erweitert und zurückgibt.

Beispiel: Der @laut-Dekorator

def laut(funktion):
    def wrapper(*args, **kwargs):
        ergebnis = funktion(*args, **kwargs)
        return ergebnis.upper()
    return wrapper

Ohne Dekorator-Schreibweise:

def gruesse(name):
    return f"Hallo, {name}!"

gruesse = laut(gruesse)
print(gruesse("Anna"))  # HALLO, ANNA!

Mit @-Schreibweise — syntaktischer Zucker für genau das Gleiche:

@laut
def gruesse(name):
    return f"Hallo, {name}!"

print(gruesse("Anna"))  # HALLO, ANNA!

Das @ vor der Funktion sagt: “Bevor du diese Funktion benutzt, schick sie zuerst durch laut hindurch.”

Dieses Prinzip funktioniert auch mit Klassen. Und genau das nutzt @dataclass.

3. @dataclass — Die Lösung

from dataclasses import dataclass

@dataclass
class Haustier:
    name: str
    tierart: str
    alter: int

Das ist alles. Fünf Zeilen statt fünfzehn.

Der Dekorator @dataclass liest die Typ-Annotationen und generiert automatisch:

  • __init__ — Konstruktor mit allen Feldern als Parameter
  • __repr__ — lesbare Ausgabe
  • __eq__ — Vergleich über alle Felder

Ausprobieren

balu = Haustier("Balu", "Hund", 3)
luna = Haustier("Luna", "Katze", 5)
balu2 = Haustier("Balu", "Hund", 3)

print(balu)          # Haustier(name='Balu', tierart='Hund', alter=3)
print(balu == luna)  # False
print(balu == balu2) # True

Wichtig zu wissen

Die Typ-Annotationen (str, int) sind keine Runtime-Checks. Python erzwingt sie nicht — sie dienen hier als Feld-Definitionen und Dokumentation. Das Folgende würde keinen Fehler werfen:

falsch = Haustier("Balu", "Hund", "drei")  # Läuft ohne Fehler

4. Wichtige Optionen und Features

frozen=True — Unveränderliche Instanzen

@dataclass(frozen=True)
class Haustier:
    name: str
    tierart: str
    alter: int

balu = Haustier("Balu", "Hund", 3)
balu.tierart = "Katze"  # FrozenInstanceError!

Balu kann nicht plötzlich zur Katze werden.

field() mit default_factory — Sichere Standardwerte

Mutable Defaults (Listen, Dicts) direkt als Standardwert zu setzen ist in Python gefährlich, weil alle Instanzen dieselbe Liste teilen würden. field() löst das:

from dataclasses import dataclass, field

@dataclass
class Haustier:
    name: str
    tierart: str
    alter: int
    tricks: list = field(default_factory=list)

balu = Haustier("Balu", "Hund", 3)
balu.tricks.append("Sitz")
print(balu.tricks)  # ['Sitz']

luna = Haustier("Luna", "Katze", 5)
print(luna.tricks)  # [] — eigene leere Liste, nicht Balus Liste

__post_init__ — Validierung nach der Erstellung

@dataclass
class Haustier:
    name: str
    tierart: str
    alter: int

    def __post_init__(self):
        if self.alter < 0:
            raise ValueError(f"Alter kann nicht negativ sein: {self.alter}")

balu = Haustier("Balu", "Hund", -1)  # ValueError!

5. Zusammenfassung

Das Problem: Klassen, die Daten halten, brauchen viel repetitiven Code.

Die Lösung: Der @dataclass-Dekorator generiert __init__, __repr__ und __eq__ automatisch aus den Feld-Definitionen.

Das Konzept dahinter: Dekoratoren sind Funktionen, die andere Funktionen oder Klassen erweitern — ohne deren Code zu verändern.

Wann @dataclass nutzen? Immer wenn eine Klasse hauptsächlich Daten hält: Konfigurationen, Ergebnisse, Zwischenspeicher, DTOs.

Alternativen: NamedTuple (unveränderlich, leichtgewichtig), attrs (mehr Features), Pydantic (mit Validierung zur Laufzeit).

Ähnliche Posts

Alle anzeigen
Closures einfach erklärt Thumbnail
App-Entwicklung pythonclosures

Python Closures: Funktionen mit Gedächtnis

Closures sind das Geheimnis hinter Decorators, Factories und elegantem State-Handling in Python. Ein praxisnaher Deep-Dive: wie sie funktionieren und wann du sie brauchst.

9 min
Python-Community

Werde Teil der Python-Community

Tausch dich mit anderen Python-Lernenden aus, stell deine Fragen im Forum und schau dir die besten Lernvideos rund um Python an — kostenlos auf Skool.