Modularisierung und Objektorientierung in Python

Dieser Artikel ist der dritte von 4 Artikeln rund um die Programmiersprache Python. Falls das Thema noch neu für dich ist, schaue am besten bei Teil 2 oder Teil 1 vorbei.

Objektorientierte Programmiersprachen erlauben es, Programme mit sehr effizienten Strukturen zu erstellen, die sich an Objekten der realen Welt orientieren. Dieser Bezug zur realen Welt macht es einfacher, den Programmcode zu verstehen. Aufgrund dieser Vorteile ist die objektorientierte Programmierung aus der modernen Informatik nicht mehr wegzudenken. Sie stellt aktuell das wichtigste Programmierparadigma dar. Darüber hinaus bietet sich die Objektorientierung hervorragend dazu an, ein Programm in einzelne Module aufzuteilen. Das sorgt insbesondere bei größeren Projekten für eine bessere Übersichtlichkeit und erleichtert die Zusammenarbeit mehrerer Programmierer.

Fast alle modernen Programmiersprachen unterstützen die objektorientierte Programmierung, auch Python.
Du kannst mit Python einfach und effizient objektorientierte Programme erstellen. Dieser Beitrag stellt vor, wie das funktioniert. Da die Objektorientierung in der Informatik ein sehr umfangreiches Thema ist, beschränkt sich dieser Beitrag auf die wichtigsten Grundlagen.

Was bedeutet objektorientierte Programmierung?

Ein typisches Szenario: Du bist Programmierer und erhältst von einem Kunden den Auftrag, ein Programm für die Verwaltung des Sortiments eines Werkzeughändlers zu schreiben. Dabei ist es unter anderem wichtig, die Eigenschaften der einzelnen Produkte zu erfassen. Beim ersten Artikel, den du in das Programm übernimmst, handelt es sich um einen Akkuschrauber. Dieser hat ein Drehmoment von 48 Nm, eine maximale Drehzahl von 1.350 Umdrehungen pro Minute, eine Spannung von 18 V und eine Akkukapazität 1,5 Ah.

Danach ist ein weiterer Akkuschrauber an der Reihe. Dieser weist andere Werte auf: ein Drehmoment von 72 Nm, eine Drehzahl von 1.500 U/min, eine Spannung von 24 V und eine Akkukapazität von 5 Ah. Trotz der Unterschiede gibt es dabei jedoch eine Gemeinsamkeit: Auch bei diesem Akkuschrauber sind das Drehmoment, die Drehzahl, die Akkuspannung und die Kapazität von Bedeutung. Bei allen weiteren Akkuschraubern im Sortiment sollen ebenfalls genau diese Werte erfasst werden.

Der Händler verkauft jedoch nicht nur Akkuschrauber, sondern noch viele weitere Werkzeuge. Im nächsten Schritt sollst du eine benzinbetriebene Kettensäge erfassen. Hierbei spielen ganz andere Werte eine Rolle. Beispielsweise ist es notwendig, die Pferdestärke,, die Schwertlänge und die Tankgröße aufzuführen. Die Angabe der Akkukapazität ist bei einer Kettensäge ohne Akku hingegen nicht sinnvoll. Die genannten Eigenschaften sind nicht nur bei einer spezifischen Kettensäge von Interesse, sondern auch bei allen weiteren benzinbetriebenen Kettensägen im Sortiment.

An diesen Beispielen erkennst du, dass du durch die Nennung der Eigenschaften die Produkte kategorisieren kannst. Das stellt die Grundidee der objektorientierten Programmierung dar. Sie erstellt Strukturen für Objekte des gleichen Typs.
Ein einzelnes Objekt (im Beispiel also ein konkreter Akkuschrauber oder eine konkrete Kettensäge) entspricht dieser Struktur, indem es für jede der vorgegebenen Eigenschaften einen konkreten Wert vorgibt. Die Höhe beispielsweise kann dabei jedoch von Objekt zu Objekt unterschiedlich sein, selbst wenn es sich dabei um den gleichen Objekttyp handelt.

Wenn du für jeden Objekttyp passende Strukturen erstellst, ist das deutlich übersichtlicher und effizienter, als einzelne Variablen oder Datenstrukturen wie Listen zu verwenden. Deshalb ist diese Vorgehensweise so weit verbreitet.

Eine Klasse als Struktur für die Objekte

Genug Theorie. Jetzt ist es an der Zeit, diese Idee in die Praxis umzusetzen.
Auch in diesem Bereich zeichnet sich Python durch einfache Regeln aus, die die Erstellung der Programme erleichtern:
Die Strukturen für die einzelnen Objekttypen erstellst du innerhalb einer Klasse. Diese führst du mit dem Schlüsselbegriff class ein. Danach folgt ein Name, den du selbst auswählen kannst und ein Doppelpunkt. Es ist üblich, dass der Name einer Klasse mit einem Großbuchstaben beginnt, um diese von gewöhnlichen Variablen zu unterscheiden. Wenn du beispielsweise wie im obigen Beispiel eine Klasse für einen Akkuschrauber erstellen willst, ist es sinnvoll, ihr genau diesen Namen zu geben:

class Akkuschrauber:

Innerhalb der Klassendefinition musst du dann einen sogenannten Konstruktor erstellen. Dieser dient dazu, ein Objekt vom Typ Akkuschrauber zu erzeugen. Dabei gibt er die passende Struktur vor.

Der Konstruktor wird immer mit dem Ausdruck def __init__ eingeleitet (vor und nach dem Ausdruck init stehen jeweils zwei Unterstriche). Danach folgt eine Klammer. Darin steht zunächst der Begriff self und danach ein Variablenname für jede Eigenschaft, die du erfassen willst. Anschließend steht wieder ein Doppelpunkt. In unserem Beispiel könnte die Einleitung des Konstruktors so aussehen:

def __init__ (self, dm, dz, sp, kap):

Wenn du später ein Objekt erstellst, musst du dabei für jede Eigenschaft einen Wert vorgeben. Das Programm übermittelt deine Angaben dann an den Konstruktor. Dieser speichert sie in den hier angegebenen Variablen. Daher kannst du innerhalb des Konstruktors unter der entsprechenden Bezeichnung auf sie zugreifen.

Nun musst du diese Werte noch an das neu zu erstellende Objekt übermitteln. Dieses ist unter dem Begriff self verfügbar – das ist auch der Grund, weshalb du diesen Ausdruck in die Klammer einfügen musstest. Danach musst du einen Punkt hinzufügen und dann den Namen der entsprechenden Eigenschaft nennen. Um vorzugeben, dass bei jedem Akkuschrauber das Drehmoment erfasst werden soll, musst du folgenden Ausdruck einfügen: self.Drehmoment. Danach weist du ihm den Wert zu, den der Konstruktor übermittelt bekommen und in der Variablen dm abgespeichert hat. Auf die gleiche Weise geben wir auch die Inhalte für die weiteren Eigenschaften vor, sodass der Konstruktor so aussieht:

self.Drehmoment = dm
self.Drehzahl = dz
self.Spannung = sp
self.Kapazitaet = kap

Die gesamte Klassendefinition sieht dann so aus:

class Akkuschrauber:
    def __init__ (self, dm, dz, sp, kap):
        self.Drehmoment = dm
        self.Drehzahl = dz
        self.Spannung = sp
        self.Kapazitaet = kap

Dabei musst du beachten, dass die Inhalte, die innerhalb der Klasse und innerhalb des Konstruktors stehen, jeweils eingerückt werden müssen. Dazu kannst du entweder die Tabulator-Taste oder jeweils die gleiche Anzahl an Leerzeichen (häufig 4 oder 8) einfügen. Daran erkennt der Python-Interpreter, dass es sich hierbei um einen zusammengehörigen Block handelt.

Ein Objekt erzeugen

Nachdem du die Klasse erstellt hast, kannst du ein Objekt erzeugen. Während die Klasse für alle Akkuschrauber gültig ist, handelt es sich beim Objekt um ein ganz konkretes Modell aus dem Sortiment. Es ist notwendig, ihm einen individuellen Namen zu geben – beispielsweise Akkuschrauber001. Indem man dieser Bezeichnung ein Gleichheitszeichen und den Namen der Klasse hinzufügt, zeigt man an, dass es sich hierbei um ein Objekt vom Typ Akkuschrauber handelt. Um das Objekt zu erstellen, muss man innerhalb einer Klammer noch die Werte der einzelnen Eigenschaften angeben:

Akkuschrauber001 = Akkuschrauber (48, 1350, 18, 1.5)

Wenn du auf diese Weise ein Objekt erzeugt hast, kannst du später auf dessen Eigenschaften zugreifen. Dazu musst du den Namen des Objekts und nach einem Punkt die Bezeichnung für die entsprechende Eigenschaft angeben. Mit diesen Informationen können wir bereits ein Programm erstellen, das eine Klasse definiert, ein Objekt erzeugt und dessen Eigenschaften ausgibt:

class Akkuschrauber:
    def __init__ (self, dm, dz, sp, kap):
        self.Drehmoment = dm
        self.Drehzahl = dz
        self.Spannung = sp
        self.Kapazitaet = kap

Akkuschrauber001 = Akkuschrauber (48, 1350, 18, 1.5)

print("Drehmoment: ", Akkuschrauber001.Drehmoment)
print("Drehzahl: ", Akkuschrauber001.Drehzahl)
print("Spannung: ", Akkuschrauber001.Spannung)
print("Kapazität: ", Akkuschrauber001.Kapazitaet)

Die Ausgabe:

Anmerkung: In den print-Befehlen geben wir zunächst einen Text und anschließend den Wert einer Variablen aus. Diese beiden Elemente verbindest du mit einem Komma.

Die Modularisierung

Ein Programm zu modularisieren, bedeutet, dass man es auf mehrere Dateien aufteilt. Das ist sehr praktisch, wenn du umfangreiche Aufgaben zu erledigen hast. In diesem Fall wäre es sehr unübersichtlich, ein einzelnes Programm mit mehreren Hunderten oder gar Tausenden Zeilen zu erstellen. Daher ist es sinnvoll, mehrere Dateien zu verwenden.

Auch wenn mehrere Programmierer zusammenarbeiten, ist das sehr zu empfehlen. Auf diese Weise ist es möglich, dass jeder einzelne an einer eigenen Datei arbeitet. Das gestaltet die Zusammenarbeit erheblich einfacher.

Die Verwendung von Klassen bietet sich hervorragend an, um ein Programm zu modularisieren. Wenn du später deine Kenntnisse ausgeweitet hast, kannst du innerhalb der Klasse auch Methoden festlegen und damit alle Abläufe steuern, die in Zusammenhang mit den verwendeten Objekten stehen. Auf diese Weise kann man weite Teile des Programms in verschiedene Klassen auslagern und für jede einzelne von ihnen eine separate Datei erstellen.

Dazu musst du in PyCharm eine neue Datei erstellen. Dafür kannst du einen beliebigen Namen auswählen. Auch die Datei für das Modul endet auf .py. Wenn sie nur eine einzige Klasse enthält, ist es üblich, den Klassennamen auch als Dateinamen zu verwenden. Daher soll die neue Datei Akkuschrauber.py heißen. In diese schreibst du nun die Klassendefinition aus dem vorherigen Programm:

class Akkuschrauber:
    def __init__ (self, dm, dz, sp, kap):
        self.Drehmoment = dm
        self.Drehzahl = dz
        self.Spannung = sp
        self.Kapazitaet = kap

Nun musst du die Datei abspeichern und schon ist das Modul fertig. Im bisherigen Programm kannst du nun den Teil, in dem wir die Klasse definiert hatten, löschen. Allerdings musst du noch dafür sorgen, dass es das Modul einliest. Sonst kann es diese externen Inhalte nicht verwenden. Dazu dient der import-Befehl – gefolgt vom Namen des Moduls ohne die Dateiendung:

import Akkuschrauber

Nun bleibt nur noch eine Kleinigkeit zu erledigen: Damit das Programm bei der Erzeugung des Objekts weiß, dass sich der Befehl auf eine Klasse aus einem anderen Modul handelt, musst du dem Klassennamen den Modulnamen voranstellen. Das Hauptprogramm sieht dann so aus:

import Akkuschrauber

Akkuschrauber001 = Akkuschrauber.Akkuschrauber  (48, 1350, 18, 1.5)

print("Drehmoment: ", Akkuschrauber001.Drehmoment)
print("Drehzahl: ", Akkuschrauber001.Drehzahl)
print("Spannung: ", Akkuschrauber001.Spannung)
print("Kapazität: ", Akkuschrauber001.Kapazitaet)

Wenn du das Programm nun erneut ausführst, erscheint genau die gleiche Ausgabe wie im vorherigen Beispiel. Allerdings haben wir den Code übersichtlich in zwei Dateien aufgeteilt.
Dieses Tutorial basiert auf dem Python Komplettkurs 2019 von Edley.

Rückmeldungen