[ Home ] [ Seitenende ] [ Teil 1 ] [ Teil 2a ] [ Teil 3 ] [ Teil 4 ]

 

 

 

Roboter-Auto „Joy-Car“ - Teil 2b

 

 

Einführung in die Objekt orientierte Programmierung (OOP)

 

Die „NeoPixel“-LEDs des „Joy-Car“-Roboters lassen sich alle mittels sogenannter Methoden wie z.B. der nachfolgenden

 

·        Methode <create(DigitalPin.P0, 8, NeoPixelMode.RGB)>

 

programmieren. Dabei spricht man von einer Methode, wenn z.B. die Funktion <create(DigitalPin.P0, 8, NeoPixelMode.RGB)> der Klasse <neopixel> zugeordnet ist, sich also die Funktion innerhalb einer Klasse befindet.

 

Eine Klasse mit ihren Methoden wiederum lässt sich zu einem Objekt instanziieren, d.h. zusammenfassen und z.B. der Instanzvariablen <strip> wie folgt zuweisen:

 

·        <strip = neopixel.create(DigitalPin.P0, 8, NeoPixelMode.RGB)>

 

Dabei verfügt ein Objekt, wie z.B. das Objekt <strip> über Attribute (= Eigenschaften) und Methoden (= Vorgehensweisen):

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Ein Objekt wie z.B. das Objekt <strip> dient also dazu, eine oder mehrere Klassen wie z.B. die Klasse <neopixel> aufzunehmen und sozusagen von außen verfügbar zu machen, ohne dass das Hauptprogramm weiß, wie genau sich das Objekt <strip> zusammensetzt, was es kann usw.

 

Demzufolge kann man sich von außen betrachtet ein Objekt als eine Art „Black Box vorstellen, die bestimmte Eigenschaften (= Attribute) hat, über bestimmte Fähigkeiten (= Methoden) verfügt und dazu bestimmte Funktionen verwendet. Dabei bezeichnet man eine Funktion innerhalb einer Klasse als Methode. Diesbezüglich kann man sich unter einer Methode die Lehre, Vorschrift, Vorgehensweise oder Anleitung zum Erreichen einer Lösung oder eines Zieles vorstellen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Jetzt hier an dieser Stelle weiter in die Objekt orientierte Programmierung (OOP) am Beispiel der Programmierung von „NeoPixel“-LEDs einzusteigen, scheint mir nicht sinnvoll und Ziel führend, da zwei komplexe Sachverhalte zusammentreffen und damit das Verständnis dieser Dinge unnötig erschweren.

 

Demzufolge ist es besser, wenn man sich zunächst stufenweise in die OOP einarbeitet. Und zwar vom Einfachen zum Schwereren, Komplexeren.

 

Nachfolgend geht es um ein Haus der Breite b, der Höhe h und der Tiefe t, sodass sich mit den entsprechenden Maßen das umbaute Volumen V wie bei einem Quader berechnen lässt: V = b * h * t .

 

Da es aber um das Erlernen der OOP geht, beginnen wir mit nur einer Variablen und zwar der Höhe h des Hauses:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_46.py)

 

Als nächstes „berechnen“ wir die Höhe h in der Methode <berechne_Haushoehe>. Das Besondere an der Methode ist, dass diese den Ergebniswert der globalen Variablen <hoehe> mittels des

 

·        Statements <return(hoehe)>

 

wieder an das aufrufende (Haupt-) Programm zurückgibt, obwohl dies eigentlich nicht notwendig wäre, da es sich bei der Variablen <hohe> um eine globale Variable handelt!

 

Wie man aber sieht, erfolgt der Methodenaufruf <berechne_Haushoehe()> nebst der Ergebnisanzeige direkt in der Stringanzeige des 5x5 Matrix LED-Displays:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_47.py)

 

Wir verbessern das obenstehende Programm dahingehend, indem wir auf die globale Variable <hoehe> innerhalb der Methode <berechne_Haushoehe(get_hoehe)> verzichten und stattdessen den Wert der Höhe = 12 m über den Methodenkopf und der lokalen Variablen <get_hoehe> wie folgt einlesen:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_48.py)

 

Wir erweitern das bisherige Programm, erzeugen die Klasse <Haus> mit zwei lokalen Variablen innerhalb der Klasse und übernehmen die ursprüngliche Funktion <berechne_Haushoehe(get_hoehe)> ebenfalls in die Klasse <Haus>, sodass diese innerhalb der Klasse <Haus> zur Methode wird:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_49.py)

 

Das Interessante an dem obenstehenden Programm ist, dass die Klasse <Haus> wider Erwarten nicht explizit aufgerufen und gestartet werden muss, sondern nach dem Programmstart ohne weiteres Zutun automatisch ausgeführt und abgearbeitet wird. Demzufolge startet sich die Methode <berechne_Haushoehe(get_hoehe)> ebenfalls automatisch, d.h. zusammen mit der Klasse <Haus>.

 

Obwohl die Methode <berechne_Haushoehe(get_hoehe)> innerhalb der Klasse <Haus> gekapselt ist, sodass man nicht so ohne Weiteres auf die Inhalte der lokalen Variablen <get_hoehe> und <ergebnis_1> von außen aus dem Hauptprogramm heraus zugreifen kann, kann man trotzdem mit dem Konstrukt <Haus.ergebnis_2> auf den Inhalt der lokalen Variablen <ergebnis_2> zugreifen (siehe roter Kasten oben im Bild). Auf diese Weise ist die Klasse <Haus> sehr mächtig, lässt sich mit dieser sehr viel anstellen und bewerkstelligen.

 

Wir steigern die Leistungsfähigkeit der Klasse <Haus>, indem wir diese von außen, d.h. vom Hauptprogramm aus, aufrufen, ausführen und dabei gleichzeitig noch den Wert 7 der lokalen Variablen <hoehe_2> mit auf den Weg geben (siehe grüner Kasten) und quasi in der Funktion <__init__(hoehe_2)> „berechnen“ und in der Laufschrift des 5x5 Matrix LED-Displays anzeigen lassen (siehe roter Kasten):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_50.py)

 

Fragen wir doch mal die Künstliche Intelligenz (KI) mit ChatGPT 4.0 der Suchmaschine „Bing von Microsoft danach, wie das obenstehende Programm funktioniert, was es genau macht:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_50.hex)

 

So, jetzt wissen wir, dass sich die (Spezial-) Funktion <__init__(hoehe_2)> auf die Klasse <Haus> bezieht und direkt an diese gekoppelt ist!

 

Dabei ermöglicht es die <init>-Funktion, dass man der Klasse <Haus> auch einen eingangsseitigen Parameter in Form eines Wertes der lokalen Variablen <hoehe_2> mit auf den Weg geben kann. Ferner wissen wir jetzt, dass es sich bei dem

 

·        Statement <Haus(hoehe_2 = 7)>

 

um ein Objekt(!) der Klasse <Haus> handelt!

 

Bei der <init>-Funktion gilt es zu beachten, dass es sich bei dem eingangsseitigen Parameter definitiv um die lokale Variablen <hoehe_2> handelt, die innerhalb der <init>-Funktion gekapselt ist, sodass man weder aus der Klasse <Haus> heraus, noch aus dem Hauptprogramm heraus auf diese zugreifen kann!

 

Aber wie wir gleich sehen werden, gibt es natürlich einen „Trick“, wie man über eine Art „Variablen-Kopplung“ dennoch auf die lokale Variablen <hoehe_2> in der <init>-Funktion zugreifen kann (siehe roter Kasten):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_51.py)

 

Als Nächstes wird der Parameter <self> quasi als Kopplungsvariable an die Klasse <Haus> in der gesamten <init>-Funktion eingesetzt.

 

Anhand des abgewinkelten roten Pfeils sieht man jetzt sehr deutlich, dass es sich bei der <init>-Funktion um den Kopfteil der Klasse <Haus> handelt, damit sich beim Aufruf des Objektes <Haus(7)> auch ein oder mehrere Parameter zwecks Initialisierung der Klasse <Haus> übergeben lassen!

 

Dabei hat der Kopfteil der Klasse <Haus> den Vorteil, dass sich in der <init>-Funktion auch weiterer Programmkode programmieren lässt:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_52.py)

 

Wir erweitern das bisherige Programm mit dem

 

·        Statement <return(ergebnis_2)>,

 

um das Berechnungsergebnis der Methode <berechne_Haushoehe()> innerhalb der Klasse <Haus> nach außen an die Instanz <h7> des Objektes <Haus()> zu übergeben! Dabei könnte man die Instanz <h7> auch als Objektvariable <h7> der Klasse <Haus> bezeichnen.

 

Aber gerade weil es sich bei der Instanz <h7> um eine Objekt-Instanz handelt, lässt sich diese nicht mittels der Scrollanzeige nach außen in der Laufschrift des 5x5 Matrix LED-Displays anzeigen, sondern nur mittels des

 

·        Konstrukts <h7.ergebnis_2>

 

(siehe ganz unten im Programmkode):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_53.py)

 

Jetzt sind wir schon mittendrin in der professionellen Objekt orientierten Programmierung (OOP) ( siehe pinkfarbener Kasten):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_54.py)

 

In dem obenstehenden Programm gibt es neben dem Objekt <h7> bzw. der Instanz <h7> auf die Klasse <Haus> auch noch zwei <def>-Konstrukte, von denen es sich bei dem einen Konstrukt um eine Funktion und bei dem anderen um eine Methode handelt. Diesbezüglich bietet es sich an, die KI von ChatGPT 4.0 der „bing“-Suchmaschine von Microsoft wie folgt zu befragen:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Jetzt wissen wir, dass es sich bei dem

 

·        <def>-Kontrukt <__init__()> um eine Funktion und bei dem

·         <def>-Kontrukt <berechne_Haushoehe()> um eine Methode handelt!

 

Generell gilt die Regel, dass eine Funktion innerhalb einer Klasse als Methode bezeichnet wird!

 

Wie wir wissen, unterscheidet man bei der Programmierung zwischen globalen und lokalen Variablen. Dabei werden Variablen, die innerhalb des Hauptprogramms deklariert und initialisiert werden als globale Variablen bezeichnet und Variablen, die innerhalb einer Funktion oder Methode deklariert und initialisiert werden als lokale Variablen.

 

Während lokale Variablen innerhalb einer Funktion oder Methode gegenüber dem Hauptprogramm gekapselt sind, sodass man von außen aus dem Hauptprogramm nicht auf diese zugreifen kann, lässt sich bei den globale Variablen von überall her auf diese zugreifen.

 

Wir erweitern das Programm „joy-car_teil_02_prog_54.hex ein weiteres Mal, indem wir die Methode <berechne_Haushoehe()>, die bisher für sich genommen völlig unabhängig von der Klasse <Haus> war, an genau diese koppeln. Dabei bezieht sich die Koppelung an die Klasse <Haus> sowohl auf die jeweilige Methode selbst, als auch auf lokale Variable im Methodenkopf sowie in der Methode selbst.

 

Diesbezüglich gibt es zwei syntaktische, satzbauliche Schreibweisen, um die Koppelung an die Klasse <Haus> vorzunehmen:

 

1.     Syntax <hoehe_2>   "   <Haus.hoehe_2> und

2.     Syntax <hoehe_2>   "   <self.hoehe_2>.

 

Beide Schreibweisen sind dabei bedeutungsmäßig und funktional identisch, wobei sich die Schreibweise gemäß 2.) durchgesetzt hat, weil man bei dieser den Klassennamen <Haus> nicht jedes Mal ausschreiben muss!

 

Bei der Programmierung der Koppelung an die Klasse <Haus> muss man sich allerdings entscheiden, ob man die Schreibweise gemäß 1.) oder 2.) verwendet! Mischformen wie z.B. <Haus.hoehe_2> und <self.hoehe_2> funktionieren dabei nicht!

 

 

Während sich beim Programmstart die Funktion <__init__()> automatisch mit dem Hauptprogramm zusammen startet, verhält es sich bei Methoden (= Funktionen innerhalb einer Klasse) nicht so, starten sich diese nicht automatisch zusammen mit dem Hauptprogramm. Vielmehr muss man Methoden sozusagen manuell starten wie z.B. mit dem

 

1.     Statement <ergebnis_2 = berechne_Haushoehe(hoehe)>

 

Und genau dies funktioniert nach der Umstellung mit der Koppelung an die Klasse <Haus> nicht mehr (siehe grüner Kasten):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_55.py)

 

In diesem Zusammenhang stellt sich nicht nur die Frage, was es mit dem <self>-Parameter genau auf sich hat, sondern

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

auch, wie sich jetzt die Methode <berechne_Haushoehe(self, hoehe)> von außen aus dem Hauptprogramm heraus aufrufen lässt.

 

Diesbezüglich wissen wir ja bereits, wie man von außen aus dem Hauptprogramm heraus auf die lokale Variable <ergebnis_2> der Klasse <Haus> zugreift:

 

2.     Statement <h7.ergebnis_2>

 

Demgemäß bietet es sich an, das vorgenannte Statement in abgewandelter Form auch auf den <Methoden>-Aufruf anzuwenden:

 

3.     Statement <h7.berechne_Haushoehe(h7.hoehe)>

 

Da die Methode <berechne_Haushoehe(self, hoehe)> innerhalb der Klasse <Haus> mittels des

 

4.     Statements <return self.ergebnis_1>

 

auch einen Ergebniswert <self.ergebnis_1> an das aufrufende Programm zurückliefert, stellt sich die Frage, wie man die Variable <self.ergebnis_1> nennen soll:

 

 

(Zum Vergrößern bitte auf das Bild klicken!)

 

Da die Methode <berechne_Haushoehe(self, hoehe)> der Klasse <Haus> mit dem

 

5.     Statement <h7.berechne_Haushoehe(h7.hoehe)>

 

vom Hauptprogramm aus aufgerufen wird und dabei gleichzeitig einen Ergebniswert an dieses zurückliefert, wählen wir die globale Variable <haus_hoehe> für die Entgegennahme des Ergebniswertes:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_56.py)

 

Jetzt wo wir wissen, wie man die Klasse <Haus> mit der Instanzvariablen <h7> zum Objekt instanziiert, können wir auch eine andere Instanzvariable wie z.B. die Instanzvariable <haus_hoehe> dem Objekt der Klasse <Haus> zuordnen:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_57.py)

 

Wenn man wissen will, ob und wie das Programm funktioniert, dann muss man sich die Mühe machen einzelnen Statements im Hauptprogramm systematisch der Reihe nach abarbeiten bzw. aufrufen. Zu diesem Zweck empfiehlt es sich immer nur ein Statement aufzurufen und dabei die anderen mittels „#“ auszukommentieren, damit man den Überblick behält.

 

Beginnen wir also mit dem

 

1.     Statement <h7 : Haus = Haus(7)>

 

Beim Start des obenstehenden Programms mit nur diesem einzelnen Statement im Hauptprogramm wird die Klasse <Haus> aufgerufen und dabei der Wert 7 als (Eingangs-) Parameter zwecks weiterer Berechnung mit übergeben. Dabei wird die Übernahme bzw. das Einlesen des Parameters mit dem Wert 7 von der Funktion <__init__()> bewerkstelligt.

 

Da die nachfolgende Methode <berechne_Haushoehe(self, hoehe)> der Klasse <Haus> an genau diese gekoppelt (= instanziiert) ist, muss die Funktion <__init__()> den eingelesenen Parameter mit dem Wert 7, der in der lokalen Variablen <hoehe_2> gespeichert wurde, ebenfalls instanziieren. Und zwar mit dem Statement <self.hoehe_2 = hoehe_2>. Dementsprechend bekommt man die Laufschriftanzeigen „1a) " 7“ und „1b) " 7“ im 5x5 Matrix LED-Display angezeigt.

 

Da aber die nachfolgende Methode <berechne_Haushoehe(self, hoehe)> nicht explizit aufgerufen wird, erfolgt auch weiter keine Laufschriftanzeige!

 

Da das

 

2.     Statement <h7.berechne_Haushoehe(h7.hoehe)>

 

die Instanziierung der Klasse <Haus> zum Objekt <Haus> mit der Instanzvariablen <h7> voraussetzt bzw. auf diese aufbaut, bekommt man als erstes die Laufschriftanzeigen „1a) " 7“ und „1b) " 7“ und anschließend „2a) " 6“ und „2b) " 9“ im 5x5 Matrix LED-Display angezeigt.

 

Das

 

3.     Statement <haus_hoehe : Haus = Haus(11)>

 

läuft wieder engl. „stand-alone“, d.h. eigenständig, ohne das 1. oder 2. Statement vorauszusetzen, obwohl die neue Instanzvariable <haus_hoehe> die gleichnamige Klasse <Haus> verwendet, aber jetzt mit dem eingelesenen Parameter und dem Wert 11, sodass man die Laufschriftanzeigen „1a) " 11“ und „1b) " 11“ im 5x5 Matrix LED-Display angezeigt bekommt!

 

Das

 

4.     Statement <basic.show_string("3a.) haus_hoehe = " + haus_hoehe.ergebnis_2 + " m")>

 

setzt wieder die Instanziierung der Klasse <Haus> zum Objekt <Haus> mit der Instanzvariablen <haus_hoehe> voraus, sodass man nur die Laufschriftanzeigen „1a) " 11“ und „1b) " 11“ angezeigt bekommt. 

 

Auch hier wird die nachfolgende Methode <berechne_Haushoehe(self, hoehe)> nicht explizit aufgerufen, sodass auch weiter keine diesbezügliche Laufschriftanzeige erfolgt!

 

Abschließend wird aber noch die Laufschriftanzeige 3a.) haus_hoehe = 11 m" angezeigt!

 

Das

 

5.     Statement <basic.show_string("3b.) haus_hoehe = "
+
haus_hoehe.berechne_Haushoehe(haus_hoehe.hoehe) + " m")>

 

setzt ebenfalls die Instanziierung der Klasse <Haus> zum Objekt <Haus> mit der Instanzvariablen <haus_hoehe> voraus, sodass man wegen des Statements <haus_hoehe : Haus = Haus(11)> als Erstes die Laufschriftanzeigen „1a) " 11“ und „1b) " 11“ angezeigt bekommt. Im Gegensatz zum 4. Statement wird aber anschließend die Methode <berechne_Haushoehe(self, hoehe)> mit dem Parameter bzw. der instanziierten Variablen <haus_hoehe.hoehe> = 6 + 3 = 9 direkt aufgerufen. Und zwar mit den Laufschriftanzeigen „2a) " 6“ und „2b) " 9“.

 

Da die Methode <berechne_Haushoehe(self, hoehe)> über das Rückgabe-Statement <return self.ergebnis_1> verfügt, wird das Berechnungsergebnis der instanziierten Variablen <self.ergebnis_1> an das aufrufende Hauptprogramm zurückgeliefert, sodass dieses Statement Nr. 5 die Laufschriftanzeige 3b.) haus_hoehe = 9 m" zur Folge hat!

 

Wenn man alle Statements im Hauptprogramm auf einmal, d.h. hintereinander, zur Ausführung bringt (siehe roter Kasten oben), dann hat dies zweifellos zur Folge, dass Laufschriftanzeigen innerhalb

 

·        der Funktion <__init__()> oder

·        der Methode <berechne_Haushoehe(self, hoehe)>

 

mehrfach angezeigt werden, sodass man schnell den Überblick verlieren kann. -

 

 

Vererben und Erben von Eigenschaften, Fähigkeiten einer Klasse zur nächsten

 

Bisher verhielt es sich so, dass mit dem

 

·        Statement <vol1 : Haus_1 = Haus_1(12, 6)>

 

und den beiden Parametern 12 (= Länge L) und 6 (= Breite B) zunächst nur die

Grundfläche = L x B in der <init>-Funktion berechnen ließ.

 

Mittels des

 

·        Statements <vol1.berechne_Hausvolumen_1(3)>

 

ließ sich in der Methode <berechne_Hausvolumen_1(self, hoehe_1)> dann auch noch das Volumen vom Objekt Haus_1 berechnen. Das ist natürlich etwas umständlich. Demzufolge ist es nur eine Frage der Zeit, dass man das Objekt Haus_1 z.B. um die Berechnung des umbauten Volumens erweitern möchte.

 

Aber anstelle das Objekt Haus_1 abzureißen und mit dem Objekt Haus_2 neu zu bebauen, bietet es sich an, das Objekt Haus_1 um einen entsprechenden Anbau zum Objekt Haus_2 zu erweitern: (siehe rote Kästen):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_58.py)

 

Wie man im obenstehenden Screenschot sieht, wird beim Objekt der Klasse <Haus_2> als Erstes der Wert = 0 m^3 der Variablen <self.volumen_2> angezeigt (siehe dunkelgrüner Kreis) und dann erst als Zweites der Wert = 150 m^3 der lokalen Variablen <volumen_2> (siehe blauer Kreis).

 

Der Grund dafür ist der, dass die

 

·        Funktion <__init__(self, laenge_2, breite_2, hoehe_2)

 

über keinen <return()>-Befehl verfügt, sodass diese quasi erst im Nachgang eingelesen wird!

 

Bei dieser Gelegenheit sei ausdrücklich darauf verwiesen, dass die <init()>-Funktion prinzipiell keinen <return()>-Befehl aufnehmen und ausführen kann, da es sich bei diesem Konstrukt um keine echte Funktion handelt, sondern um den erweiterten Kopf der Klasse, um mittels diesem beim Aufruf der Klasse mit auf den Weg gegebene Parameter einzulesen! -

 

Das obenstehende Programm wird umstrukturiert, indem eine strikte Aufgabenteilung vorgenommen und entsprechend programmiert wird.

 

Und zwar soll in der Klasse <Haus_1> mit der Methode <berechne_Grundflaeche_1(self, laenge_1, breite_1)> nur die Grundfläche des Hauses und in der Klasse <Haus_2> mit der Methode <berechne_Hausvolumen_2(self, hoehe_2)> soll nur das umbaute Volumen des Hauses berechnet werden.

 

Wenn also das Volumen berechnet werden soll, dann muss zuvor die Grundfläche des Hauses berechnet werden, da sich das Volumen aus dem Produkt von Grundfläche * Höhe berechnet. Demzufolge muss also vor der eigentlichen Volumenberechnung die Berechnung der Grundfläche gemäß der Methode <berechne_Grundflaeche_1(self, laenge_1, breite_1)> in der Klasse <Haus_1> erfolgen. Und zwar mittels des

 

·        Methodenaufrufs <grundflaeche_2 = vol1.berechne_Grundflaeche_1(vol1.laenge_1, vol1.breite_1)>,

 

der übrigens den Ergebniswert der Grundflächenberechnung zunächst an die Variable <grundflaeche_2> zurückliefert:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_59.py)

 

Im obenstehenden Sourcecode tragen alle Variablennamen, die innerhalb der Klasse <Haus_1> programmiert wurden und mit der Berechnung der Grundfläche zu tun haben mit der Endsilbe „_1“ versehen, während die Variablennamen innerhalb der Klasse <Haus_2> , die mit der Berechnung des umbauten Volumens zu tun haben mit der Endsilbe „_2“ versehen wurden!

 

Da sich alle <self>-Methoden wegen der Kopplung an die jeweilige Instanzklasse <Haus_1> oder <Haus_2> beim Programmstart nicht automatisch zusammen mit dem Hauptprogramm starten, muss man diese explizit im Hauptprogramm oder z.B. in der Methode <berechne_Hausvolumen_2(self, hoehe_2)> aufrufen und ausführen (siehe roter Kasten im Bild oben). -

 

Bisher verhielt es sich so, dass wir den Kopf der Klasse <Haus_1> oder <Haus_2> stets mittels der <init()>-Funktion konfiguriert haben (siehe roter Kasten), um dem Objekt der Klasse ein oder mehrere Parameter mit auf den Weg geben zu können:

 

·        Statement <vol1 : Haus_1 = Haus_1(12, 6)>   ó   <class Haus_1:>

 

Dabei kann man der erbenden Klasse <Haus_2> nicht nur die Eigenschaften, Funktionen und Methoden der vererbenden Klasse <Haus_1> mit auf den Weg geben, d.h. vererben, sondern auch deren (Eingangs-) Parameter im Kopf der Klasse <Haus_1(12, 6)>,

 

·        Statement <vol2 : Haus_2 = Haus_2(10, 5)>   ó   <class Haus_2(Haus_1):>

 

sodass die Parameter im Kopf der Klasse <Haus_2(10, 5)> wegen des geänderten Kopfes der Klasse <Haus_2(Haus_1)> wegen des Überschreibens(!) nicht wirksam werden:

 

·        Statement <class Haus_2(Haus_1):>

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_60.py)

 

Wie man im obenstehenden Quellkode im kleinen, grünen Kasten <(Haus_1)>) sieht, wird die Klasse <Haus_2> mittels des

 

·        Statements <class Haus_2(Haus_1):>

 

bereits auf die Erbschaft von der Klasse <Haus_1> vorbereitet. Aber es gehört natürlich noch mehr dazu, wie wir gleich sehen werden.

 

Wenn man das obenstehende Programm „joy-car_teil_02_prog_60.hex startet, dann übernimmt die Klasse <Haus_2> mit dem

 

·        Statement <grundflaeche_2 = vol1.laenge_1 * vol1.breite_1>

 

die eingangsseitigen Parameterwerte 12 und 6 der Klasse <Haus_1>, sodass sich das Volumen des Hauses wie folgt berechnet:

 

Volumen V = Grundfläche G x Höhe h = Länge x Breite x Höhe = 12 m x 6 m x 3 m = 72 m^2 x 3 m = 216 m^3

 

Mit dem nächsten Programm „joy-car_teil_02_prog_61.py lässt sich die

 

·        Methode <berechne_Grundflaeche_1B(self, laenge_1, breite_1)>

 

erstmals von der Klasse <Haus_1> an die erweiterte Klasse <Haus_2(Haus_1)> vererben.

 

Dabei gilt es zu beachten, dass sich nur Funktionen vererben lassen, die direkt mittels <init()>- und <self>-Funktion an die jeweilige Klasse angebunden sind (siehe großer grüner Kasten)! Eine solch gekoppelte Funktion nennt man dann Methode!

 

Eine an die jeweilige Klasse gekoppelte <self>-Methode lässt sich nur von außerhalb der Klasse, wie z.B. vom Hauptprogramm aus, wie folgt starten:

 

·        Statement <vol1.berechne_Grundflaeche_1B(laenge, breite)>

 

Handelt es sich bei der gekoppelten <self>-Methode um eine vererbbare <self>-Methode, dann lässt sich diese auch aus der erweiterten Klasse, wie z.B. der erweiterten Klasse <Haus_2(Haus_1)>, wie folgt aufrufen (siehe grüner Pfeil im Bild unten):

 

·        Statement <self.berechne_Grundflaeche_1B(vol1.laenge_1, vol1.breite_1)> oder

 

·        Statement <self.berechne_Grundflaeche_1B(laenge_2, breite_2)>

 

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_61.py)

 

Die oben im Quellkode zu sehende Funktion <berechne_Grundflaeche_1A(laenge_1, breite_1)> (siehe roter Kasten) ist nicht an die Klasse <Haus_1> gekoppelt, steht für sich ganz allein und lässt sich dem demzufolge nur innerhalb der Klasse <Haus_1> wie folgt aufrufen:

 

·        Statement <berechne_Grundflaeche_1A(12, 6)>. -

 

Wie man im nachfolgenden Sourcecode des Programms „joy-car_teil_02_prog_62.py sieht, lässt sich die vererbte

 

·        Methode <self.berechne_Grundflaeche_1B(laenge_2, breite_2)>

 

auch mit beliebig anderen Parameternamen nebst Werten aufrufen (siehe grüner Pfeil mit den 7   7   ):

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_62.py)

 

Wir wenden uns wieder der

 

·        Funktion <berechne_Grundflaeche_1A(laenge_1, breite_1)>

 

der Klasse <Haus_1> zu (siehe roter Kasten im Bild oben), die tatsächlich vollkommen eigenständig ist und nicht mittels <self> an die Klasse <Haus_1> gekoppelt ist, weshalb diese eben keine Methode ist! Wegen der Isoliertheit der Funktion haben wir nach wie vor das Problem, dass sich diese nur innerhalb der Klasse <Haus_1> aufrufen und ausführen lässt.

 

Ein weiteres Problem besteht darin, dass sich beim Funktionsaufruf mit dem

 

·        Statement <grundflaeche_1 = berechne_Grundflaeche_1A(12, 6)>

 

nur konstante Werte, aber eben keine Werte von Variablen als Parameter dem Funktionsaufruf mit auf den Weg geben lassen (siehe roter Kasten im Bild oben)!

 

Um diese Nachteile aus dem Weg zu räumen, und um zu einem besseren Verständnis des Ganzen zu kommen, lagern wir die

 

·        Funktion <berechne_Grundflaeche_1A(laenge_1, breite_1)>

 

kurzerhand in die neue Klasse <Haus_3> aus und benennen diese zur

 

·        Methode <berechne_Grundflaeche_1C(self)>

 

um:

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_63.py)

 

Wie man im obenstehenden Quellkode sieht, ist die ursprüngliche

 

·        Funktion <berechne_Grundflaeche_1A(laenge_1, breite_1)>

 

wegen der Kopplung an die neue Klasse <Haus_3> mittels <self>-Parameter jetzt nicht mehr isoliert

 

·        Methode <berechne_Grundflaeche_1C(self)>,

 

sodass sich auf diese von außen, d.h. z.B. vom Hauptprogramm aus, mittels des

 

·        Statements <vol3.berechne_Grundflaeche_1C()>

 

aufrufen und ausführen lässt (siehe blauer Kasten im Bild oben).

 

Da sich im Kopf der Methode <berechne_Grundflaeche_1C(self)> weiter keine Parameter mit auf den Weg geben lassen, muss man die zu berechnenden Werte mittels der Variablen <vol3.laenge_3> und <vol3.breite_3> quasi von außen zuführen bzw. zugänglich machen (siehe pinkfarbener Kasten im Bild oben)!

 

Als inzwischen erfahrener Python-Programmierer gehen wir noch einen Schritt weiter, indem wir dem obenstehenden Programm noch die

 

·        Funktion < __init__(self, laenge_3, breite_3)>

 

hinzufügen (siehe pinkfarbener Kasten),

 

 

(Vergrößern: auf das Bild klicken! | Programm „joy-car_teil_02_prog_64.py)

 

sodass sich von nun an auch Werte in Form der Parameter <laenge, breite> dem Aufruf und Ausführen der

 

·        Methode <berechne_Grundflaeche_1C(self, laenge_3, breite_3)>,

 

mit auf den Weg geben lassen (siehe unterer blauer Kasten im Bild oben)!

 

Im Vergleich mit dem Programm „joy-car_teil_02_prog_62.py bietet das weiter entwickelte Programm „joy-car_teil_02_prog_64.py den Vorteil, dass sich die Klasse <Haus_3> mit nur einem

 

·        Statement <super().__init__(laenge_3, breite_3)>

 

um die Eigenschaft des Vererbens erweitern lässt! -

 

 

 

[ Home ] [ Seitenanfang ] [Teil 1 ] [ Teil 2a ] [ Teil 3 ] [ Teil 4 ]