4.5.4 Objektstruktur & Kapselung mit privaten Attributen

In Python verwenden wir Attribute, um den Zustand eines Objekts zu beschreiben. In diesem Kapitel lernen wir, wie wir den Zugriff auf solche Attribute kontrollieren können.

🤖 Zugriff auf Attribute "von außen"

In Python können wir auf Attribute eines Objekts einfach mit objekt.attribut zugreifen, leider auch aus dem Hauptprogramm, was also von außen genannt wird.

# Klasse mit öffentlich zugänglichem Attribut (unsicher!)
# J. Thomaschewski, 29.07.2025
class Konto:
    def __init__(self):
        self.stand = 100

    def einzahlen(self, betrag):
        if isinstance(betrag, (int, float)) and betrag > 0:
            self.stand += betrag
        else:
            print("Ungültiger Betrag – bitte nur positive Zahlen!")

    def zeige(self):
        print('Kontostand: ', self.stand)


# Hauptprogramm
giro = Konto()
giro.zeige()
giro.einzahlen(50)
giro.zeige()

# Manipulation von außen (kaputt gemacht!)
giro.stand = "1.000,-- €"  # Funktioniert formal, aber inhaltlich völliger Unsinn
giro.zeige()               # Gibt sogar ein Ergebnis aus. Der Fehler kommt erst anschließend.
giro.einzahlen(50)         # Einzahlen geht jetzt nicht mehr. Fehlermeldung erst hier.
giro.zeige()

Das "Überschreiben" der Attribute direkt aus dem Hauptprogramm muss vermieden werden.

🛡️ Schutz von Attributen

Ein Attribut wird als "privat" markiert, indem wir seinem Namen zwei Unterstriche voranstellen. Das ist nützlich, wenn wir verhindern möchten, dass jemand von außen direkt darauf zugreift.

class Konto:
    def __init__(self):
        self.__stand = 100  # Startwert

    def einzahlen(self, betrag):
        if isinstance(betrag, (int, float)) and betrag > 0:
            self.__stand += betrag
        else:
            print("Ungültiger Betrag – bitte nur positive Zahlen!")

    def zeige(self):
        print("Kontostand:", self.__stand)

# Hauptprogramm
giro = Konto()
giro.zeige()
giro.einzahlen(50)
giro.zeige()

# Manipulation von außen (geht jetzt nicht mehr)
giro.stand = "1.000,-- €"  # wird einfach ignoriert. Kein Fehler, sondern einfach nichts.
giro.zeige()              
giro.einzahlen(50)         
giro.zeige()

# Man könnte noch versuchen
giro.__stand = "1.000,-- €"  # wird ebenfalls ignoriert. Kein Fehler, sondern einfach nichts.
giro.einzahlen("1.000,-- €") # gibt die schöne Fehlermeldung

Privat bedeutet hier: Es soll nicht direkt von außen verwendet werden. Python verhindert dies nicht vollständig, aber es ist eine wichtige Konvention zur sauberen Programmierung.

Privat durch Konvention

  • _attribut (ein Unterstrich) signalisiert: "geschütztes Attribut, bitte nicht von außen verwenden."
  • __attribut (zwei Unterstriche) aktiviert das sogenannte Name Mangling: Das Attribut wird intern umbenannt, sodass es schwerer zugänglich ist.

Python ist an dieser Stelle "unschöner" als andere objektorientierte Sprachen wie Java oder PHP, die einen eindeutigen Fehler ausgeben.

🔒 Getter- und Setter-Methoden

In der objektorientierten Programmierung ist es oft vorteilhaft, Attribute einer Klasse nicht direkt zugänglich zu machen, sondern den Zugriff über sogenannte Getter- und Setter-Methoden zu steuern. Dies bietet mehrere Vorteile:

  • Datenvalidierung: Bevor ein Attribut ein Wert zugewiesen wird, kann überprüft werden, ob dieser Wert gültig ist und den erwarteten Kriterien entspricht.

  • Kontrollierter Zugriff: Öffentliche Attribute können von überall gelesen und geschrieben werden. Oftmals möchte man jedoch den schreibenden Zugriff einschränken oder an bestimmte Bedingungen knüpfen.

  • Erweiterbarkeit: Durch die Verwendung von Getter- und Setter-Methoden kann später zusätzliche Funktionalität hinzugefügt werden, wie z.B. das Beobachter-Pattern, um Änderungen an Eigenschaften an andere Programmteile weiterzuleiten.

Im folgenden Python-Beispiel wird eine Klasse Student definiert, die diese Prinzipien anwendet.

class Student:
def **init**(self, name: str, matrNumber: int, phoneNumber: str):
self._name = name
self._matrNumber = matrNumber
self._phoneNumber = phoneNumber

def getMatrNumber(self):
    return self._matrNumber

def getPhoneNumber(self):
    return self._phoneNumber

def setPhoneNumber(self, newPhoneNumber):
    self._phoneNumber = newPhoneNumber

def returnNameAndMatrikel(self):
    return f"{self._name} hat die Matr.-Nr.: {self._matrNumber}"


student = Student("Marie", 7203456, "0491-23403")
print(student.getMatrNumber())
print(student.getPhoneNumber())
student.setPhoneNumber("01234 567890")
print(student.returnNameAndMatrikel())

Mit get...() geben wir einen Wert zurück, mit set...() setzen wir einen neuen Wert. Das ist das klassische Prinzip von Kapselung.

Warum Getter und Setter?

  • Wir können Werte auf Gültigkeit überprüfen, bevor sie gespeichert werden.
  • Wir behalten die Kontrolle, was ein Objekt über sich preisgibt oder verändern darf.
  • Wir können die interne Struktur später ändern, ohne das Hauptprogramm anpassen zu müssen.

📅 Zusammenfassung

Begriff Bedeutung
Attribut Ein Wert, der zu einem Objekt gehört, z. B. self.name oder self.__stand.
privat Ein Attribut, das durch zwei Unterstriche geschützt ist (__stand).
Getter/Setter Methoden, die Werte eines Attributs zurückgeben oder setzen.
Kapselung Das Prinzip, Daten im Objekt zu halten und nur über Methoden zugänglich zu machen.