Python-Grundlagen

Objektorientierte Programmierung in Python

OOP organisiert Programme als Objekte, die Zustand besitzen und Verhalten über klare Schnittstellen anbieten.

Was ist objektorientierte Programmierung in Python?

OOP modelliert ein System als zusammenarbeitende Objekte. Jedes Objekt verbindet Zustand mit zulässigen Operationen und schafft dadurch klare Verantwortungs- und Änderungsgrenzen.

Die vier OOP-Grundprinzipien

  • Kapselung: Zustand und Verhalten bündeln und nur kontrollierten Zugriff erlauben.
  • Abstraktion: eine nützliche Schnittstelle zeigen und unnötige Implementierungsdetails verbergen.
  • Vererbung: eine Klasse nur bei einer echten Ist-ein-Beziehung spezialisieren.
  • Polymorphie: dieselbe Operation auf verschiedenen Objekttypen mit passendem Verhalten verwenden.

Aufbau des Beispiels

  1. BankAccount besitzt den Kontostand und validiert Einzahlungen.
  2. SavingsAccount übernimmt den Vertrag der Basisklasse.
  3. SavingsAccount überschreibt month_end für die Verzinsung.
  4. Die Schleife nutzt alle Konten über dieselbe Schnittstelle.
Designtipp: Bevorzuge Komposition, wenn ein Objekt ein anderes nur verwendet. Nutze Vererbung nur, wenn das Kind die Elternklasse korrekt ersetzen kann.

Grundlegendes Beispiel

Code ausführen →
main.py
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self._balance = float(balance)

    @property
    def balance(self):
        return self._balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Deposit must be positive")
        self._balance += amount

    def month_end(self):
        return "No interest"


class SavingsAccount(BankAccount):
    def __init__(self, owner, balance, interest_rate):
        super().__init__(owner, balance)
        self.interest_rate = interest_rate

    def month_end(self):
        self._balance *= 1 + self.interest_rate
        return "Interest applied"


accounts = [
    BankAccount("Ada", 100),
    SavingsAccount("Lin", 200, 0.05),
]
accounts[0].deposit(50)

for account in accounts:
    status = account.month_end()
    print(f"{account.owner}: {account.balance:.2f} ({status})")

Erwartete Ausgabe

Ada: 150.00 (No interest)
Lin: 210.00 (Interest applied)

Die vier OOP-Prinzipien in der Praxis

Diese gezielten Beispiele zeigen, wie Python Kapselung, Abstraktion, Vererbung und Polymorphie im alltäglichen Code umsetzt.

Kapselung

Code ausführen →

Zustand und Verhalten bündeln und nur kontrollierten Zugriff erlauben.

encapsulation.py
class BankAccount:
    def __init__(self, balance=0):
        # Double underscores prevent accidental direct access.
        self.__balance = balance

    @property
    def balance(self):
        # Expose read access without exposing mutation.
        return self.__balance

    def deposit(self, amount):
        # Keep validation next to the state it protects.
        if amount <= 0:
            raise ValueError("Amount must be positive")
        self.__balance += amount


account = BankAccount(100)
account.deposit(50)
print(account.balance)  # 150

Abstraktion

Code ausführen →

eine nützliche Schnittstelle zeigen und unnötige Implementierungsdetails verbergen.

abstraction.py
from abc import ABC, abstractmethod


class PaymentMethod(ABC):
    @abstractmethod
    def pay(self, amount):
        # Callers know what pay does, not how each provider does it.
        pass


class CreditCard(PaymentMethod):
    def pay(self, amount):
        # The concrete class hides its payment implementation.
        return f"Paid ${amount:.2f} by card"


payment = CreditCard()
print(payment.pay(25))

Vererbung

Code ausführen →

eine Klasse nur bei einer echten Ist-ein-Beziehung spezialisieren.

inheritance.py
class Employee:
    def __init__(self, name):
        self.name = name

    def describe(self):
        return self.name


class Developer(Employee):
    def __init__(self, name, language):
        # Reuse initialization from the parent class.
        super().__init__(name)
        self.language = language

    def describe(self):
        # Extend inherited behavior instead of duplicating it.
        return f"{super().describe()} writes {self.language}"


print(Developer("Ada", "Python").describe())

Polymorphie

Code ausführen →

dieselbe Operation auf verschiedenen Objekttypen mit passendem Verhalten verwenden.

polymorphism.py
class EmailNotification:
    def send(self, message):
        return f"Email: {message}"


class SmsNotification:
    def send(self, message):
        return f"SMS: {message}"


def notify(channels, message):
    for channel in channels:
        # The same call selects behavior from each concrete object.
        print(channel.send(message))


channels = [EmailNotification(), SmsNotification()]
notify(channels, "Order shipped")

So funktioniert es

BankAccount kapselt den Kontostand. SavingsAccount erbt die Schnittstelle und überschreibt month_end. Die Schleife behandelt beide Objekte einheitlich; zur Laufzeit wird die passende Methode gewählt.

Ändere die Werte und führe das Programm im CodeUtility Python Online-Compiler aus, ohne Python lokal zu installieren.

Übungsaufgaben

Verändere Eingaben und Randfälle, bevor du die Lösung mit größeren Datenmengen testest.

  1. Sage die Ausgabe voraus, bevor du den Code ausführst.
  2. Behandle leere und ungültige Eingaben.
  3. Kapsle die Logik in einer Funktion und ergänze Tests.
In der Python-IDE ausführen →