7. Objektorientierte Programmierung
Klassen
Bisher haben wir mit einfachen Variablentypen (integer, string, boolean) und grundlegenden Datenstrukturen wie Listen und Dictionaries gearbeitet. Dabei haben wir bereits gesehen, dass viele dieser Objekte über sogenannte Methoden verfügen. So konnten wir beispielsweise mit der Methode .append() ein neues Element an eine Liste anhängen. Diese Methoden sind typisch für den jeweiligen Datentyp und ermöglichen es uns, bequem mit den enthaltenen Daten zu arbeiten.
In Python sind tatsächlich alle Variablen Objekte. Jedes Objekt besitzt bestimmte Eigenschaften (Attribute) und kann über Methoden manipuliert oder abgefragt werden.
Python erlaubt es uns jedoch nicht nur, bestehende Objekttypen zu verwenden, sondern auch eigene Datentypen zu definieren. Dies geschieht mithilfe von Klassen, einem zentralen Konzept des Programmierparadigmas der . Klassen dienen als Bauvorlage für komplexe Objekte, die sowohl Daten (Attribute) als auch Verhalten (Methoden) enthalten können. Auf diese Weise können wir reale oder abstrakte Dinge im Programm strukturiert und nachvollziehbar modellieren.
Die folgenden Analogien verdeutlichen die Beziehung zwischen einer Klasse und ihren Objekten:
Eine Klasse ist wie ein Architektur-Bauplan eines Hauses. Der Bauplan legt fest, welche Eigenschaften ein Haus besitzt (z.B. Wandfarbe, Anzahl Zimmer als Attribute) und welche Aktionen möglich sind (z.B.
tuer_oeffnen()als Methode). Der Bauplan selbst ist noch kein bewohnbares Haus, sondern lediglich die Vorlage. Erst wenn nach diesem Bauplan gebaut wird, entsteht ein konkretes Haus (Objekt). Nach demselben Bauplan (Klasse) können beliebig viele reale Häuser (Objekte) gebaut werden, die dieselbe Grundstruktur besitzen, sich aber in Wandfarbe oder Zimmeranzahl unterscheiden.Eine Klasse funktioniert auch wie ein Plätzchenausstecher (oder eine Backform). Die Metallform (Klasse) definiert die Kontur und Struktur aller Plätzchen. Jedes ausgestochene Plätzchen ist ein konkretes Objekt (eine Instanz). Alle Plätzchen teilen die gleiche Grundform, können aber individuell verziert werden (unterschiedliche Attributwerte).
Eine Klasse kann man sich zusätzlich wie eine Charaktervorlage in einem Videospiel vorstellen. Die Vorlage Krieger oder Magier definiert allgemeine Eigenschaften (z.B. Lebenspunkte, Stärke, Intelligenz) und Fähigkeiten (z.B. angreifen, heilen, zaubern). Wenn Sie im Spiel einen neuen Charakter erstellen, z.B. Irelia die Kriegerin, dann ist das ein Objekt, welches auf der Vorlage Krieger (der Klasse) basiert. Alle Krieger haben ähnliche Fähigkeiten, aber individuelle Werte.
Objekte werden in Games ständig verwendet, beispielsweise um Spieler, Gegner, Tiere, Wolken oder andere Elemente zu “spawnen”, also um diese mit zufälligen Variationen zu erzeugen. Die Grundidee von Klassen ist in Abschnitt dargestellt.
Im Grunde genommen kennen wir Klassen in Python bereits: So erstellen wir beispielsweise jedes Mal eine Instanz der Klasse list, wenn wir eine Variable des Typs list (eine Liste) erstellen (siehe Abschnitt).
Abschnitt führt bereits einige zentrale Konzepte einer Klasse ein:
Der Konstruktor
__init__: Diese spezielle Methode wird automatisch aufgerufen, sobald ein neues Objekt erzeugt wird (z.B. beianna = Person("Anna", 16)). Ihre Hauptaufgabe besteht darin, das Objekt mit Anfangswerten zu initialisieren. Die Werte in den Klammern ("Anna"und16) werden dabei als Parameter an die__init__-Methode übergeben.Die Instanzvariable
self: Das Schlüsselwortselfrepräsentiert das konkrete Objekt (die Instanz), mit dem gerade gearbeitet wird. Wird beispielsweiseanna.geburtstag_feiern()aufgerufen, verweistselfinnerhalb der Methode auf das Objektanna. Dadurch wird sichergestellt, dassself.alter += 1das Alter vonannaund nicht das eines anderen Objekts verändert.selfmuss immer der erste Parameter jeder Methode innerhalb einer Klasse sein.Attribute definieren: Innerhalb der Klasse werden Attribute eines Objekts mit
self.attributname = werterstellt. Im obigen Beispiel weistself.name = namedem Attributnamedes Objekts den übergebenen Wert zu.Auf Attribute zugreifen: Um den Wert eines Attributs innerhalb einer Methode zu lesen oder zu ändern, wird ebenfalls
self.attributnameverwendet.Methoden aufrufen: Nachdem ein Objekt erstellt wurde (z.B.
anna = Person("Anna", 16)), können seine Methoden mit der Punkt-Notation aufgerufen werden. Der Aufrufanna.geburtstag_feiern()führt die Methode für das Objektannaaus und erhöht dessen Alter.
Vordefinierte Klassen in Python
Wie bereits erwähnt ist jegliche Variable in Python ein Objekt, das zu einer bestimmten Klasse gehört. Python bietet eine Vielzahl von vordefinierten Klassen, welche wir in den vorausgehenden Kapiteln bereits angeschaut haben, beispielsweise Datentypen wie int, float, str (String), list (Liste) oder dict (Dictionary), sowie weitere Klassen. Diese Klassen haben ihre eigenen Methoden, die spezifische Operationen auf den Objekten dieser Klassen ermöglichen.
Weshalb kann man in Python eine Variable für gewisse vordefinierte Klassen erstellen, ohne explizit den Namen der Klasse anzugeben? Hier handelt es sich um etwas “Python-Magie”, bei der Python den Typ der Variable automatisch erkennt und die entsprechende Klasse verwendet. Wenn wir beispielsweise eine Variable x = 5 erstellen, wird x automatisch als Objekt der Klasse int erstellt. Python kümmert sich im Hintergrund um die Zuweisung der richtigen Klasse, sodass wir uns nicht explizit darum kümmern müssen. Wir könnten jedoch die Klasse explizit angeben, indem wir beispielsweise x = int(5) schreiben, was dasselbe Ergebnis liefert.
Wie wir gesehen haben, beinhalten gewisse Klassen bereits Methoden, wie beispielsweise .append() für Listen oder .keys() für Dictionaries. Diese Methoden sind spezifisch für die jeweilige Klasse und ermöglichen es uns, auf einfache Weise mit den Objekten dieser Klassen zu interagieren. Falls wir wissen möchten, welche Methoden eine bestimmte Klasse hat, können wir die Funktion dir() verwenden, um eine Liste aller verfügbaren Methoden und Attribute zu erhalten. Zum Beispiel:
Klassenattribute
Neben den Instanzattributen (die zu jedem einzelnen Objekt gehören) können Klassen auch Klassenattribute besitzen. Ein Klassenattribut existiert nur einmal für die gesamte Klasse und wird von allen Instanzen gemeinsam genutzt.
Vererbung und Polymorphismus
Vererbung
Ein mächtiges Konzept der Objektorientierung ist die Vererbung. Sie ermöglicht es, eine neue Klasse basierend auf einer vorhandenen Klasse zu erstellen und deren Eigenschaften und Methoden zu übernehmen.
In diesem Beispiel:
ElektroAutoerbt vonFahrzeugund erhält alle seine Attribute und Methoden.- Mit
super().__init__(...)rufen wir den Konstruktor der Elternklasse auf. - Die Methode
fahren()wird in der Kindklasse überschrieben, um die spezifische Funktionalität eines Elektroautos zu implementieren. - Mit
super().info()greifen wir auf die Methode der Elternklasse zu.
Polymorphismus
Unterschiedliche Klassen können Methoden mit denselben Namen haben, aber jede Klasse hat ihre eigene Implementierung. Dies wird als Polymorphismus bezeichnet. Das Wort Polymorphismus stammt aus dem Griechischen und bedeutet so viel wie “viele Formen”, von griechisch poly = viel und morphos = Form. Polymorphismus ermöglicht, dass verschiedene Klassen auf die gleiche Weise angesprochen werden können, obwohl sich die Methoden unterscheiden. Dies ist insbesondere bei Kindklassen von Bedeutung, die die Methoden der Elternklasse überschreiben oder auf unterschiedliche Weise implementieren können.
Praktisches Beispiel: Bibliothekssystem
Als umfassenderes Beispiel implementieren wir ein einfaches Bibliothekssystem mit mehreren Klassen, die verschiedene Aspekte einer Bibliothek modellieren.
Zusammenfassung
Die objektorientierte Programmierung mit Klassen ist ein mächtiges Werkzeug zur Strukturierung von Code und Modellierung realer Objekte. Wichtige Konzepte sind:
- Klassen definieren Vorlagen für Objekte mit Attributen und Methoden
- Objekte sind konkrete Instanzen von Klassen
- Methoden ermöglichen es, auf Attribute zuzugreifen und diese zu verändern.
- Vererbung ermöglicht die Wiederverwendung und Erweiterung von Code in Form von Kindklassen, die ihre Attribute und Methoden von Elternklassen erben und gegebenenfalls überschreiben.
- Polymorphismus ermöglicht es, Methoden mit denselben Namen in verschiedenen Klassen zu verwenden, wobei jede Klasse ihre eigene, unabhängige Implementierung hat.
Durch die Verwendung von Klassen können komplexe Systeme modelliert und implementiert werden, wodurch der Code besser strukturiert, lesbarer und wartbarer wird. Insbesondere in Games sind Klassen ein zentrales Konzept, um verschiedene Spielobjekte (wie Spieler, Gegner, Items) zu modellieren und deren Verhalten zu steuern. In der Praxis werden Klassen häufig in Kombination mit anderen Konzepten wie Vererbung und Polymorphismus verwendet, um flexible und erweiterbare Softwarearchitekturen zu schaffen.