SemaTrain Logo Ein Fachportal von SemaTrain

Objektorientierung (OOP) in Python

Sie modellieren Kurs- und Teilnehmerdaten als Objekte: Klassen, Attribute, Methoden, Kapselung – plus Vererbung, dunder-Methoden und dataclasses.

Hinweis: Beispiele nutzen Beispieldaten (didaktisch, nicht verbindlich).

Python Schulung – Kursbezug

Dieses Kapitel ist Teil des Lernpfads zur Python Schulung. Termine & Buchung laufen über SemaTrain.de.

Ziel: Sie modellieren Daten als Objekte (Teilnehmer, Kurs, Buchung) – als Basis für saubere, wartbare Python-Programme.

Merksatz: OOP ist am stärksten, wenn Sie Daten + Verhalten zusammenhalten (Attribute + Methoden) und Zustände kontrolliert ändern.

Worum geht’s?

Lehr-/Lernziele

Nach diesem Kapitel können Sie …

Wie Sie die Ziele erreichen: Wir bauen einen kleinen Kurs-/Buchungs-Use-Case (Beispieldaten). Das Quiz prüft LZ1–LZ4. Im Mini-Projekt modellieren Sie Teilnehmer + Buchung + Rabattregel.

Klasse & Objekt (Basis)

Wir modellieren einen Kurs mit Namen, Format und Beispielpreis. Die Klasse liefert außerdem eine formatierte Ausgabe.

Beispiel: Klasse Kurs (LZ1) (Python)
class Kurs:
    def __init__(self, kurs_name, format, preis_euro):
        self.kurs_name = kurs_name
        self.format = format          # "Online" oder "Praesenz"
        self.preis_euro = preis_euro  # Beispielwert

    def kurztext(self):
        return f"{self.kurs_name} | {self.format} | Preis (Beispiel): {self.preis_euro:.2f} EUR"


kurs = Kurs("Python Schulung", "Online", 1490.00)
print(kurs.kurztext())

Methoden & Kapselung (Validierung)

Statt „irgendwo“ Werte zu ändern, bündeln wir Regeln in Methoden (z.B. Rabatt begrenzen).

Methoden + Validierung (LZ2) (Python)
class Buchung:
    def __init__(self, kurs_name, preis_euro):
        self.kurs_name = kurs_name
        self.preis_euro = preis_euro  # Beispielwert
        self.rabatt_prozent = 0

    def rabatt_setzen(self, rabatt_prozent):
        # einfache Validierung/Kapselung
        if rabatt_prozent < 0 or rabatt_prozent > 30:
            raise ValueError("rabatt_prozent muss zwischen 0 und 30 liegen")
        self.rabatt_prozent = rabatt_prozent

    def endpreis(self):
        return self.preis_euro * (1 - self.rabatt_prozent / 100)

    def zusammenfassung(self):
        return f"{self.kurs_name} | Rabatt: {self.rabatt_prozent}% | Endpreis (Beispiel): {self.endpreis():.2f} EUR"


buchung = Buchung("Python Schulung", 1490.00)
buchung.rabatt_setzen(10)
print(buchung.zusammenfassung())
Optional: Property statt direktem Attributzugriff
Property mit Setter (Kapselung, LZ2) (Python)
class Buchung:
    def __init__(self, kurs_name, preis_euro):
        self.kurs_name = kurs_name
        self.preis_euro = preis_euro
        self._rabatt_prozent = 0

    @property
    def rabatt_prozent(self):
        return self._rabatt_prozent

    @rabatt_prozent.setter
    def rabatt_prozent(self, wert):
        if wert < 0 or wert > 30:
            raise ValueError("rabatt_prozent muss zwischen 0 und 30 liegen")
        self._rabatt_prozent = wert


b = Buchung("Python Schulung", 1490.00)
b.rabatt_prozent = 15
print(b.rabatt_prozent)

Vererbung & super()

Wir unterscheiden Buchungen nach Format. Online hat z.B. einen Technik-Hinweis (Beispielregel).

Vererbung + super() + __repr__ (LZ3) (Python)
class Buchung:
    def __init__(self, kurs_name, preis_euro):
        self.kurs_name = kurs_name
        self.preis_euro = preis_euro

    def hinweis(self):
        return "Allgemeiner Hinweis: Bitte Unterlagen vorab lesen."

    def __repr__(self):
        return f"Buchung(kurs_name={self.kurs_name!r}, preis_euro={self.preis_euro!r})"


class OnlineBuchung(Buchung):
    def __init__(self, kurs_name, preis_euro, meeting_link):
        super().__init__(kurs_name, preis_euro)
        self.meeting_link = meeting_link

    def hinweis(self):
        return "Online: Technik-Check (Audio/Video) vorab empfohlen."


b1 = Buchung("Python Schulung", 1490.00)
b2 = OnlineBuchung("Python Schulung", 1490.00, "https://beispiel-link.invalid")

print(b1.hinweis())
print(b2.hinweis())
print(repr(b2))

dataclasses: Datenobjekte schnell & sauber

Für „reine Daten“ (z.B. Teilnehmerprofil) sind dataclasses oft ideal.

dataclass Teilnehmer (LZ4) (Python)
from dataclasses import dataclass

@dataclass
class Teilnehmer:
    name: str
    firma: str
    erfahrungsjahre: int


tn = Teilnehmer(name="Max Beispiel", firma="Beispiel GmbH", erfahrungsjahre=2)
print(tn)  # liefert automatisch eine sinnvolle Darstellung
Optional: dataclass + Methode (kleine Logik)
dataclass mit Methode (LZ4) (Python)
from dataclasses import dataclass

@dataclass
class Teilnehmer:
    name: str
    erfahrungsjahre: int

    def ist_einsteiger(self):
        return self.erfahrungsjahre < 1


tn = Teilnehmer("Ada", 0)
print(tn.ist_einsteiger())

Praxisaufgabe (Mini)

Sie modellieren eine kleine Buchung – mit Teilnehmer, Kurs und Rabattregel (Beispieldaten).

Beitrag zu den Lehr-/Lernzielen: LZ1 (Klasse/Objekt), LZ2 (Methoden/Validierung), LZ3 (repr/Vererbung optional), LZ4 (dataclass optional).

  1. (LZ1) Klasse Kurs: kurs_name, format, preis_euro.
  2. (LZ1/LZ2) Klasse Buchung: hält Kurs + rabatt_prozent; Methode endpreis().
  3. (LZ2) Validierung: Rabatt nur 0–30%.
  4. (LZ2) Ausgabe als f-String: Kurs + Format + Endpreis (Beispiel).
  5. (Bonus, LZ4) Teilnehmer als @dataclass.
Lösungsvorschlag anzeigen
Lösung: Teilnehmer + Kurs + Buchung (Beispieldaten) (Python)
from dataclasses import dataclass

@dataclass
class Teilnehmer:
    name: str
    firma: str


class Kurs:
    def __init__(self, kurs_name, format, preis_euro):
        self.kurs_name = kurs_name
        self.format = format
        self.preis_euro = preis_euro


class Buchung:
    def __init__(self, teilnehmer, kurs):
        self.teilnehmer = teilnehmer
        self.kurs = kurs
        self.rabatt_prozent = 0

    def rabatt_setzen(self, rabatt_prozent):
        if rabatt_prozent < 0 or rabatt_prozent > 30:
            raise ValueError("rabatt_prozent muss zwischen 0 und 30 liegen")
        self.rabatt_prozent = rabatt_prozent

    def endpreis(self):
        return self.kurs.preis_euro * (1 - self.rabatt_prozent / 100)

    def zusammenfassung(self):
        ort = "remote" if self.kurs.format == "Online" else "Hamburg"
        return (
            f"TN: {self.teilnehmer.name} ({self.teilnehmer.firma}) | "
            f"Kurs: {self.kurs.kurs_name} | Format: {self.kurs.format} | Ort: {ort} | "
            f"Endpreis (Beispiel): {self.endpreis():.2f} EUR"
        )


tn = Teilnehmer(name="Max Beispiel", firma="Beispiel GmbH")
kurs = Kurs(kurs_name="Python Schulung", format="Online", preis_euro=1490.00)

buchung = Buchung(teilnehmer=tn, kurs=kurs)
buchung.rabatt_setzen(10)

print(buchung.zusammenfassung())
Optional: typische Stolperfallen
  • self vergessen: Methoden brauchen als erstes Argument self.
  • Zustand unkontrolliert ändern: lieber Methoden/Properties für Regeln (Validierung).
  • Vererbung übertreiben: oft ist Komposition (Objekt enthält Objekt) einfacher.
  • repr/str: __repr__ hilft beim Debuggen – kurz und eindeutig halten.

Kurz-Takeaways

Quiz: OOP in Python (SemaTrain-Kontext)

1. (LZ1) Wozu dient __init__ in einer Klasse?

2. (LZ2) Warum ist eine Methode wie rabatt_setzen() sinnvoll?

3. (LZ3) Was macht super() typischerweise in einer abgeleiteten Klasse?

4. (LZ4) Wofür sind dataclasses besonders geeignet?

Praxisaufgabe

Mini-Projekt: Buchungs-Manager (OOP-Use-Case)

Sie modellieren einen kleinen Buchungsfall (Beispieldaten) mit Teilnehmer, Kurs und Buchung. Dabei üben Sie Attribute + Methoden, Validierung/Kapselung, sowie optional Vererbung und dataclasses.

Beitrag zu den Lehr-/Lernzielen:
LZ1 (Klassen/Objekte)   LZ2 (Methoden, Validierung/Kapselung)   LZ3 (dunder, Vererbung optional)   LZ4 (dataclasses für Datenobjekte).

Aufgabe

Lösung anzeigen
Lösung: Buchungs-Manager (OOP komplett: dataclass, Kapselung, dunder, Vererbung) (Python)
from dataclasses import dataclass


# (LZ4) Datenobjekt
@dataclass
class Teilnehmer:
    name: str
    firma: str
    erfahrungsjahre: int = 0


# (LZ1) „Logik-/Domänenklasse“
class Kurs:
    def __init__(self, kurs_name: str, format: str, dauer_tage: int, preis_euro: float):
        self.kurs_name = kurs_name
        self.format = format            # "Online" oder "Praesenz"
        self.dauer_tage = int(dauer_tage)
        self.preis_euro = float(preis_euro)

    def __repr__(self) -> str:
        # (LZ3) Debug-freundlich
        return (
            f"Kurs(kurs_name={self.kurs_name!r}, format={self.format!r}, "
            f"dauer_tage={self.dauer_tage!r}, preis_euro={self.preis_euro!r})"
        )


# (LZ2) Buchung kapselt Regeln/Zustand
class Buchung:
    def __init__(self, teilnehmer: Teilnehmer, kurs: Kurs):
        self.teilnehmer = teilnehmer
        self.kurs = kurs
        self._rabatt_prozent = 0

    # (LZ2) Kapselung + Validierung
    def rabatt_setzen(self, rabatt_prozent: int) -> None:
        if rabatt_prozent < 0 or rabatt_prozent > 30:
            raise ValueError("rabatt_prozent muss zwischen 0 und 30 liegen")
        self._rabatt_prozent = int(rabatt_prozent)

    @property
    def rabatt_prozent(self) -> int:
        return self._rabatt_prozent

    def rabatt_automatisch(self) -> None:
        # Beispielregel: Online & >= 3 Tage => 10% Rabatt
        if self.kurs.format == "Online" and self.kurs.dauer_tage >= 3:
            self.rabatt_setzen(10)
        else:
            self.rabatt_setzen(0)

    def endpreis(self) -> float:
        return self.kurs.preis_euro * (1 - self.rabatt_prozent / 100)

    def tagespreis(self) -> float:
        return self.endpreis() / self.kurs.dauer_tage

    def hinweis(self) -> str:
        return "Allgemeiner Hinweis: Unterlagen vorab lesen."

    def __str__(self) -> str:
        # (LZ3) „schöne“ Ausgabe
        ort = "remote" if self.kurs.format == "Online" else "Hamburg"
        return (
            f"TN: {self.teilnehmer.name} ({self.teilnehmer.firma}) | "
            f"Kurs: {self.kurs.kurs_name} | {self.kurs.format} | Ort: {ort} | "
            f"Dauer: {self.kurs.dauer_tage} Tage | Rabatt: {self.rabatt_prozent}% | "
            f"Endpreis (Beispiel): {self.endpreis():.2f} EUR | "
            f"/Tag: {self.tagespreis():.2f} EUR"
        )


# (Bonus, LZ3) Vererbung / Spezialisierung
class OnlineBuchung(Buchung):
    def __init__(self, teilnehmer: Teilnehmer, kurs: Kurs, meeting_link: str):
        super().__init__(teilnehmer, kurs)
        self.meeting_link = meeting_link

    def hinweis(self) -> str:
        return "Online: Technik-Check (Audio/Video) vorab empfohlen."

    def __repr__(self) -> str:
        return (
            f"OnlineBuchung(teilnehmer={self.teilnehmer!r}, kurs={self.kurs!r}, "
            f"meeting_link={self.meeting_link!r}, rabatt_prozent={self.rabatt_prozent!r})"
        )


# ===== Demo (Beispieldaten) =====
tn = Teilnehmer(name="Max Beispiel", firma="Beispiel GmbH", erfahrungsjahre=2)
kurs = Kurs(kurs_name="Python Schulung", format="Online", dauer_tage=3, preis_euro=1490.00)

buchung = OnlineBuchung(teilnehmer=tn, kurs=kurs, meeting_link="https://beispiel-link.invalid")
buchung.rabatt_automatisch()

print("DEBUG:", repr(kurs))
print("HINWEIS:", buchung.hinweis())
print(str(buchung))
print("DEBUG BUCHUNG:", repr(buchung))