|
[ Home ] [ Seitenende ]
|
|
|||||
|
Micropython, Teil 3 Im zweiten Teil dieses Tutorials sind wir beim Programm „micro_python-hallo_2-40.py“
stehengeblieben bei dem es darum ging, eine übergeordnete Instanz namens „Instanz_Klasse_1“ anzulegen und der
untergeordneten Klasse „Klasse_1“ zuzuordnen. Den Vorgang nennt man
deshalb auch „Instanziieren“ oder „Instanzierung“. Was aber soll man sich unter einer Instanz
vorstellen? Bezüglich der Judikation, d.h. des Rechtswesen und der
Rechtsprechung hatten wir das ja schon besprochen. Nämlich wenn man gegen ein
Urteil z.B. des örtlich ansässigen Amtsgerichtes Widerspruch einlegt, dann
geht es mit dem Verfahren zur nächst höheren Instanz wie z.B. dem
Landgericht. Im Mittelalter und auch noch heutzutage gibt
es den Volksspruch: „Gehe nicht zu deinem Fürst, wenn du nicht gerufen
wirst!“ Damit ist gemeint, dass man nicht die nächst höhere Instanz, wie z.B.
den Chef, wegen jeder Kleinigkeit oder Unzufriedenheit aufsuchen und diesen
behelligen soll. Diesbezüglich gibt es noch eine weitere Volksweisheit: „Was
der Chef nicht weiß, macht ihn nicht heiß!“ Das bedeutet, dass der Chef als
nächst höhere Instanz nicht alles wissen muss, nicht über alles bis ins
Detail informiert sein muss. Schließlich verfügt jeder Mitarbeiter im Betrieb
um sein heimliches „Herrschaftswissen“, das er den anderen aus taktischen und
strategischen Gründen vorenthält. Kurz und gut, eine Instanz ist einfach etwas
Höheres, was auch immer das konkret sein mag. Man könnte es also auch im
einen oder anderen Fall als Wichtigtuerei abtun. Bei der Programmierung
jedenfalls steht eine Instanz über einer Klasse und eine Klasse
über einer Funktion (siehe Programm „micro_python-hallo_3-1.py“).
Und, wenn es eine Instanz
zu einer Klasse gibt und die
Klasse wiederum eine untergeordnete Funktion enthält, dann spricht man nicht
mehr von einer Funktion, sondern von einer Methode
(= „gewusst wie“, Anleitung, Rezeptur zwecks Erreichen eines Ziels oder, um
ein bestimmtes, vorgegebenes Produkt nach Vorgabe zu produzieren). Demzufolge
ist eine Methode programmiertechnisch
stets das Zusammenspiel zwischen einer Klasse
und einer untergeordneten Funktion. Im Programm
„micro_python-hallo_3-1.py“
gibt es nun zwei Instanzen, und zwar zu jeder Klasse eine: · Instanz
„Instanz_Klasse_1“ zur „Klasse_1“ und · Instanz
„Instanz_Klasse_2“ zur „Klasse_2“. Mittels der beiden Instanzen können wir nun sowohl auf die Klasse „Klasse_1“ und deren untergeordneten Funktion „Funktion_1()“ als auch auf die Klasse „Klasse_2“ und deren untergeordneten Funktion „Funktion_2()“ zugreifen und dabei
mittels des · Statements „Instanz_Klasse_2.EmpfangsVar = Instanz_Klasse_1.SendeVar“ einen Datenaustausch von der Variablen „SendeVar“ zur Variablen „EmpfangsVar“ vornehmen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie wir bereits wissen, werden Klassen beim Programmstart automatisch im Hintergrund aufgerufen und
ausgeführt, sodass diese vom Hauptprogramm
aus nicht explizit aufgerufen werden müssen. So weit der Vorteil von Klassen. Aber wo Licht ist, ist auch Schatten, lassen
sich Klassen nicht per se
ein weiteres Mal aufrufen und ausführen! Es sei denn man programmiert um die Klassen herum eine entsprechende Funktion! Funktionen haben nämlich den Vorteil, dass sie sich jederzeit
z.B. vom Hauptprogramm aus beliebig oft aufrufen und ausführen lassen!
Mit samt den darin befindlichen Klassen, die beim Funktionsaufruf ebenfalls mit
ausgeführt werden (siehe Programm „micro_python-hallo_3-2.py“):
(Zum Vergrößern bitte
auf das Bild klicken!) Wenn man aber wie im obenstehenden Programm „micro_python-hallo_3-2.py“
um die beiden Klassen „Klasse_1“ und „Klasse_2“ eine entsprechende Funktion
drum herum programmiert, dann kommt man auf herkömmliche Weise wider Erwarten
nicht mehr so ohne Weiteres an die Variablen nebst Variableninhalte innerhalb
einer Klasse. Es sei denn, man
greift zu einem kleinen Trick und lässt sich die Variableninhalte mittels des „return“-Statements z.B. an das Hauptprogramm wieder zurückgeben
(siehe grüne Kästen im obenstehenden Bild): (Zum Vergrößern bitte
auf das Bild klicken!) Der entscheidende Nachteil der zuvor genannten
Methode, Variableninhalte über das „return“-Statement nach außen zu
transferieren, ist leider der, dass man dazu stets die entsprechende Methode selbst aufrufen muss. In der
Programmierpraxis gibt es aber oft Situationen, wo genau das nicht
erwünscht oder sogar unmöglich ist. Wie man sieht, kommt das Programm „micro_python-hallo_3-3.py“
ganz ohne des „return“-Statements zwecks Transferierens von Dateninhalten aus,
weil die ehemalige, äußere Funktion „tausche_Daten()“ durch die äußere Klasse „Container_Klasse“ ersetzt wurde: (Zum Vergrößern bitte
auf das Bild klicken!) Bei genauerem Studium des obenstehenden
Quellkodes fällt auf, dass die lokale Variable
„lokale_EmpfangsVar“ in der Methode „Funktion_2()“ in Wirklichkeit leer ist bzw. den Variableninhalt „…“ enthält, weil sich der Variableninhalt „Ich bin
Text aus der Funktion 1!“ der Variablen „lokale_SendeVar“ →
„SendeVar“ →
„SendeVar = Klasse_1.SendeVar“ wider Erwarten nicht
der Variablen „EmpfangsVar“ innerhalb der Klasse „Klasse_2“ zuweisen lässt! Diesbezüglich stellt sich dann gleich die
Frage, wie die Variable „EmpfangsVar“ trotzdem zum Variableninhalt „Ich bin Text aus der Funktion 1!“ kommt! Ganz einfach: durch das · Statement „Instanz_Container.EmpfangsVar = Container_Klasse.SendeVar“ (siehe
grüner Kasten im Hauptprogramm): (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Programmkode sieht,
wird die Klasse „Klasse_2“ überhaupt nicht mehr gebraucht,
weil der Datentransfer von der Variablen „SendeVar“ zur Variablen „EmpfangsVar“ zwischen den Instanzen „Container_Klasse“ und „Instanz_Container“ erfolgt (siehe Programm „micro_python-hallo_3-4.py“).
Von
Instanzen zum Objekt orientierten Programmieren (OOP) So, nun sind wir ohne es zunächst bemerkt zu
haben, beim Programmieren von Objekten angekommen. Wie aber
ist das möglich? Was ist überhaupt ein Objekt?
Und wie wird aus einer Instanz ein Objekt? Erinnern wir uns:
Zur besseren Veranschaulichung stelle man sich
folgendes vor: Ein mehrköpfiges Programmierteam hat im Laufe von mehreren
Jahren ein umfangreiches „Python“-Programm, das aus mehreren Modulen und
zehntausenden von Programmzeilen Kode besteht, programmiert und erfolgreich
abgeschlossen, d.h. auf den Kunden losgelassen. Nach fünf Jahren meldet sich der Kunde wieder
und möchte sein diesbezügliches Programm um etliche Funktionen erweitert
haben, sodass dieses entsprechend leistungsfähiger wird. Das Problem dabei
ist aber, dass es die damaligen Programmierer aus dem Programmierteam nicht
mehr gibt! Aber nicht, weil sie gestorben sind, sondern weil diese
zwischenzeitlich zu anderen Firmen gewechselt sind. Demzufolge müsste sich
das neue Entwicklerteam, dass das Programm des Kunden nicht programmiert hat,
über mehrere Monate komplett neu in den Sourcecode einlesen und einarbeiten
mit der unangenehmen Konsequenz, dass mit den vom Kunden gewünschten
Erweiterungen praktisch ein komplett neues Programm entstehen würde. Wider
Erwarten ist dem aber nicht so, weil die Programmierer in den Modulen
sämtliche übergeordneten Klassen und Funktionen zu entsprechenden Objekten instanziieren, die sich jederzeit problemlos
um weitere Funktionen, Attributen usw. ergänzen lassen, ohne
dass die ursprünglichen Klassen-Instanzen „angefasst“ werden
müssen! - Beim Programm
„micro_python-hallo_3-6.py“
wird die übergeordnete Klasse „Container_Klasse“ zunächst mittels des ·
Statements „Objekt_Container = Container_Klasse()“ zum Objekt
„Objekt_Container“ instanziiert und anschließend
mittels des ·
Statements „Objekt_Container.Neue_ObjektVar = ’Ich bin neuer Content des Objekts 'Objekt_Container'!\n’
“ um die Objektvariable
„Neue_ObjektVar“ nebst Content ergänzt
(siehe roter Kasten): (Zum Vergrößern bitte
auf das Bild klicken!) Die Funktion
„Funktion_2(get_InputVar)“ innerhalb der Klasse „Klasse_2“ dient lediglich dazu, um aufzuzeigen, wie man den
Variableninhalt der Objektvariable „Neue_ObjektVar“ quasi nach außerhalb
des Hauptprogramms zur Anzeige
bringt. - Mit dem Programm
„micro_python-hallo_3-7.py“
lässt sich zeigen, dass das Objekt „Objekt_Container“ zwar von der
instanziierten Klasse „Container_Klasse“ alle Attribute usw.
erbt, aber umgekehrt die Klasse „Container_Klasse“ leer ausgeht, wenn
man das Objekt „Objekt_Container“ z.B. um die Objektvariable „Neue_ObjektVar“ nebst Textstring „Ich
bin neuer Content des Objekts 'Objekt_Container'!“ erweitert: (Zum Vergrößern bitte
auf das Bild klicken!) Beim Instanziieren
einer übergeordneten Klasse (oder Funktion), d.h. der Vererbung von Eigenschaften der Klasse an das entsprechende
Objekt, ist es wie im richtigen Leben: erben tun immer nur die
Hinterbliebenen, d.h. die Objekte, während der Spender selbst, d.h. die
instanziierte Klasse, leer ausgeht, nicht bedacht wird, wenn sich das Objekt
„vergrößert“. Bildlich gesprochen sozusagen. Aber wie man anhand des Programms „micro_python-hallo_3-8.py“
sieht, gibt es, ebenfalls wie im richtigen Leben, einen
Gerechtigkeitsausgleich, gibt es ein Geben und Nehmen zwischen dem Spender,
d.h. der instanziierten
Klasse
und dem Empfänger, d.h. dem begünstigten
Objekt
(siehe roter Kasten im nachfolgenden Screenshot): (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man also das Objekt „Objekt_Container“ z.B. um die Objektvariable „Neue_ObjektVar“ nebst Textstring „Ich
bin neuer Content des Objekts 'Objekt_Container'!“ erweitert, dann erweitert
sich im Umkehrschluss auch die Instanz-Klasse
„Container_Klasse“ um den Variableninhalt der Klassenvariable „Neue_ObjektVar“: In diesem Zusammenhang stellt sich
abschließend die Frage, wie man das ·
Konstrukt „Objekt_Container = Container_Klasse“ jetzt nennen soll. Da von der übergeordneten Klasse „Container_Klasse“ kein neues Objekt „Objekt_Container“ instanziiert wird, handelt es sich bei dem
neuen Konstrukt „Objekt_Container“ ebenfalls um eine
übergeordnete, instanziierte Klasse!
- Was
haben Objekte und das OOP mit dem „Internet of Things“ zu tun? Wenn man einen Bekannten danach fragt, was ein
Objekt ist oder sein könnte, dann wird er sagen, dass man einen Gegenstand
als Objekt bezeichnen kann, weil man diesen auch anfassen kann. Wenn man also
einen Gegenstand anfassen kann, dieser also gegenständlich ist, dann ist er
ein Objekt. Und, wenn man einen Gegenstand anfassen kann, dann liegt er je
nach Form und Struktur, d.h. Beschaffenheit, mehr oder weniger gut in der
Hand. Demzufolge hat ein Gegenstand nicht nur ein Äußeres, eine Gestalt, die
sich anfassen lässt, sondern auch Eigenschaften wie z.B. eine bestimmte
Farbe, je nach Material auch einen bestimmten Geruch. Neue Möbel aus
Pressspan z.B. riechen weniger nach Holz als viel mehr nach Formaldehyd, der
die nächste Zeit erst noch ausdünsten muss, weshalb man anfangs öfters lüften
sollte. Neuwagen, d.h. neue PKWs, werden seitens des Herstellers Duft
optimiert, damit man das billige Plastik des Armaturenbretts nicht als
störend empfindet. Ähnlich verhält es sich bei Limousinen der Ober- oder
Luxusklasse, deren Autotüren bezüglich des Geräusches beim Schließen
ebenfalls akustisch optimiert werden, indem man diese mit einem Hohlkörper
versieht, dessen Resonanz beim Schließen der Tür einen kräftigen, sonoren und
damit wertigen „Wumms“ erzeugt. - Wenn man jemanden fragt, was „IoT“ bedeutet,
dann fällt den meisten Mitmenschen dazu nichts ein, können diese mit der
Abkürzung „Internet of Things (IoT)“ nichts anfangen. Auch dann nicht, wenn
man ihnen die Abkürzung ins Deutsche übersetzt. Eigentlich müsste es ja auch
„Internet der Dinge und Dienste“ heißen, weil die Dinge, d.h. die
Objekte nicht wirklich intelligent sind. Objekte wissen deshalb erst dann wer
und was sie sind, wenn man sie mit ihrer elektronischen und/oder digitalen
Schnittstelle mit einem Computer, d.h. einem Server über das Internet
verbindet. Der Server ist es nämlich, der dem Objekt „sagt“, was es für ein
Objekt ist, was es für Eigenschaften (= Attribute) und Fähigkeiten (=
Methoden) hat. Vorteilhaft ist es deshalb, wenn man selbst schon mal einen
Server (Webserver, E-Mail-Server, NAS) betrieben hat. Demzufolge wissen auch
viele nicht, dass ihre heimische FRITZ!Box nicht nur als WLAN-fähiger
DSL-/VDSL-Router arbeitet, sondern eben auch als sogenannter NAS-Server
im lokalen, d.h. heimischen Netzwerk (LAN) mittels dem sich Audio- und
Videodateien auf den Desktop-PC, Notebook, das Tablet-PC oder Smartphone
streamen lassen. Vorausgesetzt natürlich, dass man einen USB-Speicher oder eine
USB-Festplatte mit Audio-/Videodateien, Fotos, Musik, aber auch Text- oder
PDF-Dateien an die FRITZ!Box
als NAS-Server anschließt. Dazu sollte man dann auch wissen, was „NAS“
bedeutet, nämlich „Network Attached Storage“ im Sinne
eines netzwerkfähigen USB-Speichers im lokalen Netzwerk (LAN) oder Internet
(„MyFRITZ!“).
- Auch wenn viele Menschen nicht wissen, was
„IoT“ bedeutet, so gibt es doch einige von ihnen, die mit „Industrie 4.0“ oder „Arbeit 4.0“ etwas anfangen
können. Diesbezüglich wäre aber wichtig zu wissen, dass alle Begriffe mit ein
und derselben Sache zu tun haben, nämlich der „Vierten, industriellen
Revolution!“. Es ist also nur eine Frage der Zeit, wann die FRITZ!Box auch
zum heimischen IoT-Server wird, der Kühlschrank, Kaffeemaschine,
Waschmaschine, Rollladensteuerung, die Steuerung des farbigen Lichts im
smarten Zuhause miteinander vernetzt und miteinander kommunizieren
lässt. So wie es aber im Moment aussieht, wird Google mit „Google Nest Hub“,
der smarten, sprachgesteuerten Vernetzung der heimischen Umgebung das Rennen
machen. Nicht zuletzt wegen des vielen Kapitals, das Google in Google Nest
investieren kann, sondern auch wegen des Betriebssystems von Google Android
mit dem Google
Assistenten. Dazu muss man wissen, dass die „Alexa“-Konkurrenz von
Amazon die weniger gute „Bing“-Suchmaschine von Microsoft verwendet und eben
über kein universelles „Android“-Betriebssystem nebst künstlicher Intelligenz
in Form des „Google Assistenten“ verfügt. - Kraftfahrzeuge
nicht nur als Objekt der Begierde Wenn es also darum geht, in die Objekt
orientierte Programmierung (OOP)
einzusteigen, dann wird das am besten gelingen, wenn die Objekte leben,
lebendig und anschaulich sind. Oder aber umstritten, wie z.B. die SUVs, die
wegen ihrer vielen PS und des hohen Schadstoffausstoßes extrem klimaschädlich
und gesundheitsgefährlich sind. Kurz und gut, bei den PKWs, wie z.B. Limousinen, Sportwagen,
SUVs, Kleintransportern, Oldtimern, und LKWs geht es, wie der Name schon
sagt, um (Kraft-) Fahrzeuge, die
über einen eigenen Antrieb verfügen und von Otto-, Diesel- oder
Elektromotoren angetrieben werden. Demzufolge gibt es eine Klasse „PKW“
und eine Klasse „LKW“ und die darüber
befindliche Basisklasse „Fahrzeuge“:
Alle Fahrzeuge verfügen über die grundlegende
Eigenschaft, dass sie beschleunigen und bremsen können. Demzufolge positionieren
wir die Methoden „beschleunigen()“ und „bremsen()“ oberhalb der Klassen „PKW“ und „LKW“:
Wenn man das Programm „micro_python-hallo_3-9.py“
startet, dann stellt man fest, dass sich in der Klasse „Fahrzeuge“ noch nichts
tut, was ja auch nicht weiter verwunderlich ist, weil es ja noch keine
Fahrzeuge gibt. Wenn wir jetzt zwei PKWs der Marke „VW“ und
„BMW“ kaufen und dem Fuhrpark hinzufügen, dann stellt sich die Frage, wie wir
diese der Klasse „PKW“ hinzufügen. Naheliegend wäre z.B. dass wir
diese innerhalb der Klasse „PKW“ namentlich aufführen, im Sinne von erwähnen
(siehe Programm „micro_python-hallo_3-10.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Aber die Namensangabe in Form des Textstrings
„Volkswagen“ der Variablen „vw“ wäre dann nichts anderes als ein
Namensschild, eine Namensangabe oder ein Namenslabel (= Etikett, Aufkleber,
Aufdruck). Damit wäre dann gerade einmal der Name als Attribut (=
Eigenschaft) eines Objektes vom Typ „PKW“ festgelegt. Aber bei der Variablen
„vw“ handelt es sich um eine Stringvariable und noch nicht um ein
Attribut zum Objekt „vw“ vom Typ „PKW“. Diesbezüglich müssen wir also das Label „Volkswagen“ zu einem Attribut des Objektes „vw“
machen. Und zwar mit den Statements · vw = PKW() und · vw.label = “Volkswagen“ Dabei wird die Objektvariable „vw“ mit dem ersten
Statement zu einem Bestandteil der Klasse
„PKW“. Und mit dem zweiten
Statement, das das erste Statement zwingend voraussetzt, wird die Stringvariable „label“ zum ersten Attribut
des Objektes „vw“ der Klasse
„PKW“. In diesem Zusammenhang stellt sich dann gleich
die Frage, an welcher Stelle wir die beiden Statements im Programmkode
unterbringen müssen. Wenn es also ein neues Objekt „vw“ der Klasse „PKW“
geben soll, dann muss die Klasse
„PKW“ zuvor schon existent
sein. Demzufolge müssen die beiden Statements als Programmkode ans Ende der Klasse „Fahrzeuge“ wie folgt positioniert werden: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man sich die Bildschirmanzeige des Programm „micro_python-hallo_3-11.py“
anschaut, (Zum Vergrößern bitte
auf das Bild klicken!) dann bestätigt sich, dass das Objekt „vw“
tatsächlich zur Klasse „PKW“ gehört. Im Programm
„micro_python-hallo_3-12.py“
wird die Anzeige einzelner Attribute „label“, „kfztype“,
„leistung“ der Objekte „vw“ und „bmw“
ans Ende der Klasse „Fahrzeuge“ verfrachtet. Das Bemerkenswerte dabei
ist, dass die Klasse „PKW“ nur gebraucht wird, um diese zu deklarieren,
sodass in dieser selbst kein Programmkode generiert wird! Demzufolge
dient die Klasse „PKW“ nur dazu, um die Objekte „vw“ und „bmw“ anlegen zu können, indem die Klasse selbst instanziiert wird, sodass diese
zur Instanz für die Objekte selbst
wird: (Zum Vergrößern bitte
auf das Bild klicken!) Der Nachteil beim obenstehenden Programm „micro_python-hallo_3-12.py“
ist noch der, dass man sich die Attribute
„label“, „kfztype“ und „leistung“ nur einzeln anschauen bzw. zur Anzeige bringen
kann. Vorteilhafter wäre es natürlich, wenn man sich die Attribute auch als
Ganzes, z.B. in Form einer Auflistung, anzeigen lassen könnte. Beim Programm
„micro_python-hallo_3-13.py“
werden die einzelnen Attribute „label“, „kfztype“ und „leistung“ in der „tuple“-Liste „attribute“ zusammengefasst. Und
zwar für jedes der Objekte „vw“ und „bmw“: (Zum Vergrößern bitte
auf das Bild klicken!) Beim Programm
„micro_python-hallo_3-14.py“
werden die Attribute „marke“, „label“, „kfztype“ und „leistung“ nebst der „tuple“-Liste „attribute“ in die Funktion „festlegen_Attribute(self, marke, parameter)“
ausgelagert: (Zum Vergrößern bitte
auf das Bild klicken!) Dabei werden Funktion „festlegen_Attribute(self, marke, parameter)“ insgesamt drei Parameter mit auf den Weg gegeben, damit sich „return“-Rückgabe der Funktion flexibel
handhaben lässt. Dabei legt man mit dem ersten Parameter „self“ fest, welchem Objekt „vw“
oder „bmw“ welche Attribute
zugewiesen werden sollen. Der zweite Paramter „marke“ dient als
Unterscheidungsmerkmal, welchem Objekt
(„vw“ oder „bmw“) welche Attribute
„marke“, „label“, „kfztype“ und „leistung“ nebst der „tuple“-Liste
„attribute“ dem Objekt mit auf den Weg gegeben werden
sollen. Mit dem dritten Parameter „0“, „1“, …, „4“
wird dann festgelegt, welches Attribut mittels „return“-Statement aus der Attributeliste „Attribute“ zurückgegeben werden soll. Dabei steht
„0“ für „alle
Attribute“ sollen zurückgegeben werden, „1“
bis „4“ jeweils nur „ein
Attribut“ entsprechend der Position
in der Attributeliste „Attribute“: (Zum Vergrößern bitte
auf das Bild klicken!) Als nächstes lassen wir den Golf 1.0 TSI mit
66 kW von 0 auf 100 km/h beschleunigen. Dazu braucht das Fahrtzeug eine
Beschleunigungszeit von ta = 9,9 s. Dabei berechnet sich die Beschleunigung
mittels der Formel v = a * t → a = v / t = 100 km/h
/ 9,9 s = 100 * 103 m/3600 s
) / 9,9 s = 100 * 1 m/3,6 s
/ 9,9 s = 100 m / 3,6 s / 9,9 s = 2,81 m/s2
Wenn man den Golf weiter bis zur
Endgeschwindigkeit vEnd mit vEnd = 196
km/h = 196 * 1000 m / 3600 s = 196 * 1 beschleunigen lässt, dann hat er bis zum
Erreichen der Höchstgeschwindigkeit die Zeitdauer t = 19,4 s zurück gelegt: v = a * t → t = v / a = 54,4 m/s / 2,81
m/s2 = 19,4 s Während dieser Zeit hat er eine Entfernung von
v = s / t → s = v * t = 54,4 m/s * 19,4 s = 1.055,36 m = 1,1 km zurück gelegt. - Kennen Sie den Unterschied zwischen einer gleichförmigen
und ungleichförmigen Beschleunigung? Bei einer gleichförmigen
Beschleunigung ist die Beschleunigung selbst immer gleich groß, d.h. konstant,
sodass sie sich demzufolge nicht ändert. Das Verblüffende daran ist
nun, dass das Fahrzeug beim Beschleunigen immer schneller wird, mehr Fahrt
aufnimmt, obwohl sich an der Beschleunigung mit agleich = konstant
selbst nichts ändert, weil diese ja konstant ist. Bezüglich der
Beschleunigung könnte man nämlich aus der Beobachtung und aus der Erfahrung
heraus meinen, dass das Fahrzeug nur deshalb schneller wird, weil es immer
stärker beschleunigt. Aber genau das ist nicht der Fall, weil zu der
aktuellen (Momentan-) Geschwindigkeit durch die Beschleunigung fortwährend
noch ein weiterer Geschwindigkeitszuwachs - nicht Beschleunigungszuwachs - von ∆v = agleich * ∆t hinzu kommt: v = v0 + a * t mit v0 =
Anfangsgeschwindigkeit. Bei einer ungleichförmigen Beschleunigung ändert sich die Beschleunigung fortwährend, sodass diese eben nicht
mehr konstant ist wie bei der gleichförmigen Beschleunigung. Bei einer Rakete
zum Beispiel ändert sich die Beschleunigung fortwährend, sodass diese größer
wird, die Rakete mehr und mehr stärker beschleunigt, weil sich die
Kraftstofftanks entleeren und die Rakete dabei an Gewicht
und damit an Masse verliert. So, nachdem wir nun wissen, wie eine
gleichförmige Beschleunigung funktioniert und sich recht einfach berechnen
lässt, machen wir uns daran und programmieren wir diese innerhalb der Funktion „darf_beschleunigen()“: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man sich das Programm „micro_python-hallo_3-15.py“
anschaut, dann fällt sofort auf, dass zu Beginn des Programms die beiden Module „time“
und „_thread“ importiert werden, um
sie später im Hauptprogramm nutzen
zu können. Dabei stellt sich gleich die Frage, was ein „_thread“
ist (man beachte den Unterstrich!). Wenn man „thread“ wortwörtlich übersetzt,
dann heißt es auf Deutsch „Faden“: >>
In der Informatik bezeichnet Thread [θɹɛd] (englisch thread, ‚Faden‘, ‚Strang‘)
auch Aktivitätsträger oder leichtgewichtiger Prozess genannt –
einen Ausführungsstrang oder eine Ausführungsreihenfolge in der
Abarbeitung eines Programms. Ein Thread ist Teil eines Prozesses. Es wird zwischen zwei Arten von Threads unterschieden: 1.
Threads im engeren Sinne, die
sogenannten Kernel-Threads, laufen ab unter Steuerung durch das Betriebssystem. 2.
Im Gegensatz dazu stehen die sogenannten User-Threads,
die das Computerprogramm des Anwenders komplett selbst verwalten muss. << (Quelle: Wikipedia) Sicherlich haben Sie schon etwas von „Multitasking“ gehört.
Dabei ist aber nicht das Multitasking der Frauen gemeint, die vermeintlich
mehrere Aufgaben so ganz nebenbei bewerkstelligen können. So weit ich
informiert bin und richtig gelesen habe, gibt es beim Menschen, also weder
bei Frauen noch Männern, echtes Multitasking. Man kann zwar beim Arbeiten,
Lösen der Hausaufgaben oder z.B. Programmieren nebenbei Musik hören und damit
die andere Gehirnhälfte aktivieren, sodass sich bei Lernprozessen beide
Gehirnhälften besser untereinander vernetzen und Gelerntes ggf. besser
speichern. Ein kleines Beispiel bzw. Witz für das
unterschiedliche Arbeiten beider Gehirnhälften: „Bei einem Stotterer brennt
zu Hause die Küche, weil er das Braten der Bratwurst zu lange unbeaufsichtigt
ließ, sodass sich das Fett in der Bratpfanne entzündete. Als er mit der
Notrufnummer 112 die Feuerwehr zur Hilfe rufen will, fällt ihm ein, dass er
wegen der Aufregung des Küchenbrandes und seiner Stotterei keinen richtigen
Satz herausbekommt, sodass ihn der Feuerwehrmann am anderen Ende der Leitung
absolut nicht versteht, wohin sie fahren und den Brand löschen soll. Zum
Glück fällt ihm aber rechtzeitig ein, dass er als Stotterer einfach nur zu
singen braucht, um sich verständlich mitzuteilen, da beim Singen die andere
Gehirnhälfte aktiv ist und Stotterer beim Singen eben nicht stottern! Also
ruft der Stotterer die Feuerwehr an und singt ins Telefon: ‚Es
breeeeennnnntttt, es breeeennnnntttt, es breeeennnt!’ Da tönt es am anderen
Ende der Telefonleitung: ‚Fiderallala, fiderallala, fiderallalalala!’ und der
Hörer wurde aufgelegt.“ Wenn also der Stotterer beide Gehirnhälften
benutzt, indem er singt und dabei quasi Multitasking betreibt, ist dies bei
dem Feuerwehrmann am Telefon genau nicht der Fall. Multitasking beim „Windows-“ oder „Linux-“
Betriebssystem bedeutet, dass sich der (Rechen-) Prozessor aufteilt und quasi
gleichzeitig mehrere Aufgaben, d.h. Programme ausführt und bedient. In
Wirklichkeit aber wird das Multitasking nur dem Anwender vorgegaukelt. Dazu muss man wissen, dass Prozessorkerne
nebst Rechenwerk (ALU = engl. „Arithmetic Logic Unit“, d.h. „Arithmetische
Logikeinheit“) sehr schnell rechnen können, weil sie nur zwei Finger anstelle
von zehn besitzen, d.h. binär mit Nullen und Einsen rechnen. Demzufolge gibt es für den Rechenknecht, d.h.
die CPU (= engl. „Central Processor Unit“, d.h. Zentrale Prozessoreinheit“)
eine sogenannte Zeitscheibe, die sich beim Bewältigen mehrerer Aufgaben
entsprechend aufteilt und zwar ähnlich einer unterteilten Erdbeertorte. Praktisch bedeutet dies, dass sich der
Prozessor zeitlich immer nur einen kurzen Moment einer Aufgabe widmet
und bezüglich der 360 Grad Zeitscheibe im Laufe eines Umlaufs dabei aber
insgesamt mehrere Aufgaben quasi gleichzeitig (aus der Sicht des
Anwenders), in Wirklichkeit aber nacheinander (aus der Sicht des Prozessors
und der Zeitscheibe) bearbeitet. Ähnlich verhält es sich bei einem oder
mehreren Threads bei der Python-Programmierung. Anschaulich könnte man sagen,
dass das Threading bei einem Python-Programm dem Multitasking eines
Betriebssystems entspricht. Und das ist schon eine tolle Sache! Man kann im
Python-Programm einen Prozess anstoßen, um diesen dann parallel im
Hintergrund laufen und ausführen zu lassen. Wenn man z.B. einen Bewegungssensor ständig
abfragt, ob es eine Bewegung gibt oder nicht, dann soll dieser Vorgang eben
nicht ständig das Hauptprogramm stören und unterbrechen. Aus diesem Grund
lässt man dann die Abfrage des Bewegungssensors in einem Thread im
Hintergrund laufen. Erst, wenn es wirklich eine maßgebliche Bewegung gibt,
wird vom Thread ein Ereignis gemeldet, das vom Hauptprogramm entgegen
genommen und bearbeitet wird. Aber das Ereignis gesteuerte Programmieren
scheint dann doch ein Thema für sich zu sein, dem es sich zu gegebener Zeit
zu widmen gilt. - Zurück zum Programm „micro_python-hallo_3-15.py“
und zur Methode „darf_beschleunigen()“ bei der die Endgeschwindigkeit „v_ende“ anhand der der Beschleunigung a = 2,81
m/s^2
des VW Golf 8, Typ 1.0 TSI und der Beschleunigungszeit von 19,4 s berechnet wird. Dabei wird die
Beschleunigungszeit des VW Golf der Einfachheit halber von 100 km/h bis zum
Erreichen der Höchstgeschwindigkeit
von 196 km/h hochgerechnet und
dabei so getan als würde der VW Golf durchgehend gleichförmig, d.h. konstant
beschleunigt. Da wir es bei dem Programm „micro_python-hallo_3-16.py“
mit mehreren Objekten und zwar dem Objekt „vw“ und „bmw“ der Klasse
„PKW“ zu tun haben und bei
diesen unterschiedliche Fahrzeugparameter verwendet werden, ist es an der
Zeit, dass wir die entsprechenden Fahrzeugattribute in der Methode „festlegen_Attribute(self, marke, parameter)“
wie folgt speichern: (Zum Vergrößern bitte
auf das Bild klicken!) Da es zu der Klasse „PKW“ die beiden Objekte „vw“
und „bmw“ gibt, spricht man von
der Methode „festlegen_Attribute(self, marke, parameter)“! Dabei wird die „tuple“-Attributeliste „attribute“ zunächst lokal innerhalb der Methode
abgespeichert und später beim Methodenaufruf mittels des · Statements „self.attribute
= attribute“ einem der beiden Objekte „vw“ oder „bmw“ zugewiesen, sodass das jeweilige Objekt
später über entsprechende Eigenschaften verfügt! Mit dem · Statement „return(attribute_Objekt)“ erfolgt dann der Rücksprung wieder in die Klasse
„Fahrzeuge“, wo die Attributeliste des jeweils aufgerufenen Objektes „vw“
oder „bmw“ innerhalb der Klasse gespeichert wird und dieser
damit zur Verfügung steht. - Im Programm
„micro_python-hallo_3-17.py“
wird die Attributeliste um die Attribute „beschleunigung“ und „max_geschwindigkeit“ erweitert, sodass sich mit diesen rechnen und
in der Methode „darf_beschleunigen()“ die
Beschleunigungsdauer und die dabei erreichte Höchstgeschwindigkeit berechnen
lassen. Damit sich der · Thread „_thread.start_new_thread(darf_beschleunigen, ( ) )” zusammen mit der ·
Methode „darf_beschleunigen()” vom Hauptprogramm
aus aufrufen lässt, müssen wir zuvor die Attributeliste der Klasse „Fahrzeuge“ für das Hauptprogramm verfügbar machen. Der Knackpunkt dabei ist der, dass die Übergabeparameter der Methode „darf_beschleunigen()“ nur in Form einer „tuple“-Liste „( )“ beim
Starten des Threads übergeben
werden dürfen: ·
Thread „_thread.start_new_thread(darf_beschleunigen, (beschleunigungKFZ,
max_geschwindigkeitKFZ) )” (Zum Vergrößern bitte
auf das Bild klicken!) Wie man anhand des Programms „micro_python-hallo_3-18.py“
sieht, geht es auch kompakter: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn also die Daten der „tuple“-Attributeliste
„attribute“ nicht explizit
im Hauptprogramm benötigt werden,
dann muss man diese auch nicht zwingend vor dem Starten des Threads für das Hauptprogramm
verfügbar machen (siehe roter Kasten im obenstehenden Bild). Im vorherigen Programm „micro_python-hallo_3-17.py“
wurde die „tuple“-Attributeliste „attribute“ hauptsächlich nur deshalb für das Hauptprogramm verfügbar gemacht, weil es darum ging herzufinden,
wie man das Ganze handwerklich/programmiertechnisch bewerkstelligen muss und
umsetzen kann, da Daten-/Variableninhalte usw. innerhalb einer Methode einer
Klasse sehr gut nach außen hin zum Hauptprogramm
gekapselt sind! Schwierig, da neu und ungewohnt, ist es auch
deshalb, weil wir die beiden Objekte „vw“ und „bmw“
der Klasse „PKW“ zugeordnet haben, die wiederum zur übergeordneten
Klasse „Fahrzeuge“ gehört. Das ist dann auch der Grund dafür, dass man
dem Objekt „vw“ oder „bmw“
die Angabe der übergeordneten Klasse
„Fahrzeuge“ voranstellen muss: · Fahrzeuge.darf_beschleunigen · Fahrzeuge.festlegen_Attribute(Fahrzeuge.vw, "VW", 4) … und nicht: · vw.darf_beschleunigen · vw.festlegen_Attribute(vw, "VW", 4) Beim Programm
„micro_python-hallo_3-19.py“
geht es darum, dass wir das Hauptprogramm
aufräumen, indem wir das ·
Statement „_thread.start_new_thread(darf_beschleunigen, ( … ) )” ans Ende der Klasse „Fahrzeuge“ auslagern: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man sich die beiden „thread“-Statements im Programm „micro_python-hallo_3-18.py“
(siehe im Bild weiter oben)
und im Programm „micro_python-hallo_3-19.py“
(siehe obenstehendes Bild) anschaut und miteinander vergleicht, dann fällt
sofort auf, das letzteres am einfachsten und übersichtlichsten ist. - Das Statement
„time.sleep(5)“ am Ende des
Hauptprogramms ist notwendig, damit der Thread eventuell auf andere Threads
wartet und nicht sofort beendet wird. Alle Threads eines Programms werden nämlich sofort abgebrochen,
wenn das Hauptprogramm sein Ende erreicht hat. Mit dem Modul „threading“ lassen sich bessere Methoden anwenden, um einen Thread auf das Ende eines anderen warten zu lassen.
- Mit der Objekt orientierten Programmierung
(OOP) haben wir im Programm „micro_python-hallo_3-20.py“
zunächst die beiden Objekte „vw“ und „bmw“
der Klasse „PKW“ erzeugt, die wiederum zur Oberklasse „Fahrzeuge“ gehört. Diesen Vorgang nennt man
übrigens Instanzen
einer Klasse
erzeugen. - Wie wir bereits wissen, verfügen Objekte über Eigenschaften, die man bei der OOP als Attribute bezeichnet: (Zum Vergrößern bitte
auf das Bild klicken!) Als ein beispielhaftes Attribut sei hier die Variable „beschleunigung_a“ des VW Golf 1.0 TSI
benannt, der mit 2,81 m/s^2 auf 100 km/h beschleunigt. Mittels der Formel v = a * t lässt sich dann die dazu erforderliche Beschleunigungszeit bzw. -dauer tB1 wie folgt berechnen: tB1 = v / a = 100 km/h
/ 2,81 m/s2 = 100 10 = 27,78 / 2,81 s = 9,89 s Da die Maximalgeschwindigkeit des VW Golf 1.0
TSI aber 196 km/h beträgt, lässt sich dieser auch über die 100 km/h hinaus
weiter bis zum Erreichen der Höchstgeschwindigkeit beschleunigen, sodass sich
die Beschleunigungszeit entsprechend vergrößert: tB2 = v / a = 196 km/h
/ 2,81 m/s2 = 196 10 = 54,44 / 2,81 s = 19,37 s Wie man unschwer sieht, gibt es zum Objekt „vw“
und „bmw“ nicht nur statische
Attribute, sondern bezüglich des
Fahrens und der Fahrphysik auch dynamische wie z.B. die
Beschleunigungszeit von 0 auf 100 km/h bzw. 196 km/h. Dass sich ab etwa 100
km/h der Luftwiderstand des Objektes erhöht und das Fahrzeug
demzufolge länger braucht, um die Höchstgeschwindigkeit von 196 km/h zu
erreichen, versteht sich von selbst, soll aber der Einfachheit halber
unberücksichtigt bleiben. Bezüglich der fahrdynamischen Attribute gibt
es im Wesentlichen drei Gruppen und zwar: Ein Auto · steht, wartet, · fährt vor- oder
rückwärts, · beschleunigt oder
bremst. Dabei hat das Auto beim Vor- oder
Rückwärtsfahren jeweils eine Anfangsgeschwindigkeit v0, eine
mittlere Geschwindigkeit vMittel, eine Momentan- oder
Maximalgeschwindigkeit vmax. Beim Beschleunigen oder Verzögern/Bremsen gibt
es die Beschleunigung a, die Beschleunigungsdauer t und den
Geschwindigkeitszuwachse ∆v
am Ende der Beschleunigung. Dabei hat die Beschleunigung a beim
Verzögern/Bremsen sowie bei der Geschwindigkeitsabnahme einen negativen
Koeffizienten. (Zum Vergrößern bitte
auf das Bild klicken!) Wie man anhand des Programms „micro_python-hallo_3-21.py“
sieht, lassen sich die dynamischen Attribute noch weiter untergliedern: (Zum Vergrößern bitte
auf das Bild klicken!) Allerdings hat das Programm
„micro_python-hallo_3-21.py“ noch einen entscheidenden „Schönheitsfehler“.
Und zwar den, dass die Attributslisten
in den roten Kästen von den booleschen
Attributen im grünen
Kasten
überschrieben werden (siehe obenstehendes Bild)! Da wir aber noch lernen müssen, wie man von
außen auf die Liste mit den dynamischen Attributen und deren Variablen zugreifen
kann, entscheiden wir uns im Programm
„micro_python-hallo_3-22.py“
zunächst für die einfachere Variante mit dem grünen Kasten: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man sich dann noch die Bildschirmausgabe
des Programms „micro_python-hallo_3-22.py“
anschaut, (Zum Vergrößern bitte
auf das Bild klicken!) dann wird sofort klar, dass die dynamische Attributeliste „dyn_Attribute“ (siehe grüner Kasten im obenstehenden
Screenshot) nicht besonders selbsterklärend bzw. anschaulich ist. Bei der Frage
„Ist VW größer als BMW?“ mit der Antwort „True“
handelt es sich nicht um einen Größenvergleich beider
Automobilhersteller, sondern vielmehr um die · Abfrage „Fahrzeuge.vw.dyn_Attribute >
Fahrzeuge.bmw.dyn_Attribute“. Dabei werden die dynamischen Attribute der beiden Objekte „vw“ und „bmw“ miteinander verglichen. Und zwar als Ganzes,
d.h. in Form der Liste, könnte man meinen. Aber in Wirklichkeit wird nur die Reihenfolge, d.h. die programmiertechnische Abfolge der beiden Objekte „vw“ und „bmw“ miteinander verglichen: (Zum Vergrößern bitte
auf das Bild klicken!) Mit dem Programm
„micro_python-hallo_3-23.py“
wird die Anzeige der dynamischen
Attribute
schon wesentlich aussagekräftiger und anschaulicher: (Zum Vergrößern bitte
auf das Bild klicken!) Beim Programm
„micro_python-hallo_3-24.py“
werden die Statements zwecks Anzeige der dynamischen Attribute aus dem Hauptprogramm
entfernt und am Ende der Klasse
„Fahrzeuge“ wieder eingefügt:
(Zum Vergrößern bitte
auf das Bild klicken!) Als nächstes werden wir im Programm „micro_python-hallo_3-25.py“
konkreter, indem wir mehr ins Detail gehen und Berechnungen hinsichtlich der
Beschleunigung, der Beschleunigungsdauer und der dabei erreichten
Geschwindigkeit anstellen. Dabei kommen dann auch die dynamischen, d.h.
veränderlichen Attribute-Listen „bewegt_sich“, „beschleunigt“ und „geschwindigkeit“ der Objekte „vw“
und „bmw“ zum Einsatz: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man anhand des nachfolgenden Screenshots
sieht, beschleunigen beide (Fahrzeug-) Objekte
„vw“ und „bmw“ insgesamt 4,94 Sekunden lang und erreichen
wegen des unterschiedlich großen Beschleunigungsvermögens im gleichen Zeitrum
auch dementsprechend unterschiedlich große Geschwindigkeiten von 50 km/h bzw. 58,2 km/h: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man bei der obenstehenden Berechnung und der
dazugehörigen Anzeige sieht, erreicht der „VW Golf 1.0 TSI“ die innerörtliche Höchstgeschwindigkeit von
50 km/h nach 4,94
Sekunden.
Diesbezüglich erreicht der schnellere „BMW 1 F40“ wegen seiner größeren Beschleunigung
von 3,27 m/s2 die „50 km/h“-Marke in deutlich kürzerer Zeit: v
= a * t → t = v / a = 50 km/h / 3,27 m/s2 = 50 * 10 Da es sich bei der Beschleunigung eines PKWs
um einen temporären Vorgang, d.h. Ereignis handelt, macht es, wenn es um die
Objekt und Ereignis orientierte Programmierung geht, wenig Sinn, wenn man
einen solchen dynamischen und zeitlich befristeten Vorgang statisch und
zeitlich bis zur Unendlichkeit bzw. bis zum Stromausfall programmiert. Mit
anderen Worten: Wenn wir das Programm
„micro_python-hallo_3-25.py“
starten, dann wird jedes Mal der Beschleunigungsvorgang ausgelöst, egal, ob
dieser irgendwann einmal schon stattgefunden hat oder nicht. Objekte und deren Attribute mit Verfallsdatum Zwar lassen sich Beschleunigungsvorgänge
beliebig oft wiederholen, sind aber wegen der jeweils unterschiedlichen
Verkehrssituationen und Reaktionen auf diese individuell unterschiedlich und
damit für sich genommen einmalig. Um deutlich zu machen, dass es sich bei einem
Beschleunigungsvorgang um einen zeitlich befristeten und in seiner
Individualität und Einmaligkeit einzigartig stattfindenden Vorgang handelt,
werden wir diesem symbolisch ein Verfallsdatum geben. Und zwar in dem Sinne,
dass der Beschleunigungsvorgang deklariert, initialisiert, angestoßen,
abgearbeitet, beendet und anschließend gelöscht wird. Zum Beschleunigen braucht es im vorliegenden
Fall ein Fahrzeug bei dem es sich programmiertechnisch um ein Objekt handelt,
das über verschiedene statische und dynamische Eigenschaften im Sinne von
Attributen verfügt. Beim Programm „micro_python-hallo_3-26.py“
wenden wir erstmals einen sogenannten „Konstruktor“ als besondere Methode (=
Funktion innerhalb einer Klasse) an, um dem Objekt PKW eine Lebensdauer,
sozusagen ein Verfallsdatum, zu verpassen. Dabei handelt es sich nicht
wirklich um ein kalendarisches Verfallsdatum,
sondern vielmehr um eine Aktion bei der das entsprechende Objekt verfällt,
d.h. das Zeitliche segnet, wenn es seinen Zweck erfüllt hat. Was aber ist ein „Konstruktor“? Im
Lateinischen bedeutet „con“ wortwörtlich „mit“. Demzufolge geht es beim
Konstruktor oder Konstrukt um etwas Zusammenhängendes, etwas
Zusammengesetzes. Ein Konstrukt fügt also bestimmte Dinge bzw. Attribute zum
Objekt hinzu. Die Aufgabe von Konstruktoren ist es also, Objekte in einen
definierten Anfangszustand zu bringen und so benötigte Ressourcen zu
reservieren, sofern diese zum Zeitpunkt der Objekterstellung bereits bekannt
sind: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Quellkode sieht, wird
die Geschwindigkeit „a_geschwindigkeit“ als Funktion der
Beschleunigung als auch der Beschleunigungsdauer berechnet und mittels „return“-Statement zurückgegeben, sodass
der nachfolgende Konstruktor „__str__(a_geschwindigkeit)“ auf das Ergebnis
zugreifen und dieses auf den Bildschirm anzeigen kann: (Zum Vergrößern bitte
auf das Bild klicken!) Mit dem Konstruktor
„__str__(a_geschwindigkeit)“ kann man sich also jederzeit anzeigen lassen,
ob das Attribut „a_geschwindigkeit“ noch existent ist oder
nicht. Im Falle aber, dass das Attribut
„a_geschwindigkeit“ nicht mehr existiert,
weil es zwischenzeitlich gelöscht wurde, gibt es eine entsprechende Fehlermeldung. Was jetzt noch fehlt ist der Konstruktor „__del__()“ mit dem sich z.B. das Attribut „a_geschwindigkeit“ löschen lässt. Dazu muss noch ergänzt werden,
dass sich im Konstruktor „__del__()“ selbst nur Attribute löschen lassen, nicht jedoch das dazugehörige Objekt „vw“
als Instanz der Klasse „PKW“: (Zum Vergrößern bitte
auf das Bild klicken!) Da wir die beiden Objekte „vw“ und „bmw“ nicht antasten wollen, legen wir im Hauptprogramm das neue Objekt „ego“ als Instanz der Klasse „Fahrzeuge“ (nicht der Klasse „PKW“) an. Und zwar mit dem · Statement „ego =
Fahrzeuge(a_dauer, a_beschleunigung)“ Da wir das Objekt „ego“ als Instanz der Klasse „Fahrzeuge“ beschleunigen lassen wollen und dazu dann auch die
Beschleunigung berechnen müssen, geben wir der Klasse noch
die beiden Variablen „a_dauer“ für die Beschleunigungsdauer und „a_beschleunigung“ für die Beschleunigung des Fahrzeugs „ego“ mit auf
den Weg. Dabei sind die beiden Variablen „a_dauer“ und „a_beschleunigung“ keine Attribute des Objekts
„ego“, sondern Variablen der Klasse
„Fahrzeuge“! Dabei stellt sich dann gleich die Frage, wo
und wie sich die Geschwindigkeit als Funktion der Beschleunigung und der
Beschleunigungsdauer berechnen lässt. Nämlich im Konstrukt „__init__(self,
a_beschleunigung, a_dauer)“ innerhalb der Klasse „Fahrzeuge“: (Zum Vergrößern bitte
auf das Bild klicken!) Bei der Berechnung der Geschwindigkeit „a_geschwindigkeit“ ist besonders
interessant, dass das Konstrukt „__init__(self, a_beschleunigung, a_dauer)“
wider Erwarten nicht explizit aufgerufen/gestartet werden muss, um die
Geschwindigkeit zu berechnen, da das Konstrukt, d.h. die besondere Methode,
beim Programmstart automatisch
als Erstes ausgeführt wird (siehe Programm
„micro_python-hallo_3-27.py“).
Das gilt aber auch für alle anderen Methoden innerhalb der Klasse „Fahrzeuge“. Auch diese starten sich automatisch beim Programmstart. Beim Programm
„micro_python-hallo_3-28.py“
kommen erstmalig zwei neue Statements zum Einsatz und zwar das · Statement „del ego.a_geschwindigkeit“ und das · Statement „del ego“. Dabei wird beim ersten Statement „del ego.a_geschwindigkeit“ das Attribut
„a_geschwindigkeit“ des Objektes „ego“
aus der Klasse „Fahrzeuge“ gelöscht. Diesbezüglich steht nämlich
die engl. Abkürzung „del“ für „delete“, d.h. löschen, entfernen. Das Statement
„del ego.a_geschwindigkeit“ findet sich mit „#“ auskommentiert im Konstrukt „__del__()“ der Klasse „Fahrzeuge“. Und zwar auskommentiert deshalb, weil
es bei der Aktivierung/Umsetzung bei der weiteren Programmausführung des
Sourcecodes zu einer entsprechenden Fehlermeldung führt. Das Statement
„del ego“ findet sich mit „#“
auskommentiert im Hauptprogramm
und sorgt dafür, dass das neue Objekt „ego“ der Instanz
„Fahrzeuge“ komplett gelöscht
wird, sodass dieses demzufolge bei der weiteren Programmausführung nicht mehr
zur Verfügung steht und beim Aufruf der nachfolgenden Konstrukte „Fahrzeuge.__del__()“ und „Fahrzeuge.__str__()“ im Hauptprogramm zu
einer entsprechenden Fehlermeldung führt. Das ist dann
auch der Grund dafür, weshalb es zunächst im Quellkode mit „#“ auskommentiert
wurde. Auf Dauer sind die Fehlermeldungen natürlich sehr lästig, da ja schließlich der
Programmablauf unterbrochen wird. Beim Programm
„micro_python-hallo_3-29.py“
gibt es diesen Nachteil nicht mehr, da Fehlermeldungen, die den Programmablauf unterbrechen, indem
diese das entsprechende Programm kurzerhand beenden, mittels „Versuch und
Irrtum“ unterbunden werden. Genau genommen müsste es aber „Versuch und
Ausnahme“, engl. „try and exception“, heißen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Programmkode sieht,
sorgt das · Statement „del self.a_geschwindigkeit“ dafür, dass das Attribut „a_geschwindigkeit“ des Objektes „ego“
gelöscht wird, sodass sich die Geschwindigkeit nicht mehr im · Statement „print("Die
Geschwindigkeit beträgt noch immer:", self.a_geschwindigkeit, "km/h\n")“ anzeigen lässt und es im Normalfall aufgrund einer
entsprechenden Fehlermeldung zum Programmabbruch käme. Es kommt aber nicht
zur Fehlermeldung nebst Programmabbruch, da dieser durch das „except“-Statement (=
„ausgenommen“-Statement) abgefangen wird und stattdessen die Meldung „Das Attribut 'a_geschwindigkeit' existiert NICHT mehr!“ angezeigt wird (siehe
obenstehendes Bild). Selbstverständlich lässt sich das „try and except“-Verfahren auch im Hauptprogramm anwenden, um das
komplette Objekt „ego“ inkl. aller Attribute zu löschen (siehe Programm
„micro_python-hallo_3-29.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Nachdem wir nun wissen, was es mit den Konstrukten „__init__()“, „__del__()“ und „__str__()“ auf sich hat, wozu sich diese einsetzen lassen und auch
wissen, dass sich mit dem „try and
except“-Verfahren sehr einfach Fehlermeldungen nebst Programmausstiege abfangen lassen,
machen wir uns ein weiteres Mal an die Arbeit und räumen das Hauptprogramm auf, indem wir den
dortigen Programmkode in die Klasse „Fahrzeuge“ wie folg verlagern (siehe Programm „micro_python-hallo_3-30.py“): (Zum Vergrößern bitte
auf das Bild klicken!) In diesem Zusammenhang wird nun das Objekt „ego“,
d.h. der kleine Elektro-Stadtflitzer,
in der Klasse „PKW“ instanziiert: (Zum Vergrößern bitte
auf das Bild klicken!)
Dass dem wirklich so ist, lässt sich zeigen,
indem man sich die Variableninhalte im Hauptprogramm wie folgt mit dem · Statement print("Die Beschleunigung des 'ego'
beträgt:", Fahrzeuge.a_beschleunigung, "m/s^2") anzeigen lässt (siehe Programm „micro_python-hallo_3-31.py“).
Im Gegensatz dazu lässt sich das Attribut „a_geschwindigkeit“ (= Variable
„a_geschwindigkeit“ des Objektes „ego“
wie folgt mit dem · Statement print("Die Geschwindigkeit des 'ego'
beträgt:", Fahrzeuge.ego.a_geschwindigkeit, "km/h\n") anzeigen: (Zum Vergrößern bitte
auf das Bild klicken!) Dass wir nur über die übergeordnete Klasse „Fahrzeuge“ an die Variableninhalte der Klasse selbst als auch an die der
Objekte in Form der Attribute ist dem Umstand der
Objekt orientierten Programmierung (OOP) geschuldet, derzufolge die Klasse „Fahrzeuge“ eben die übergeordnete Klasse zu den Unterklassen „PKW“, „LKW“, „E-PKW“ oder „E-LKW“ usw ist. Besonders interessant und wichtig ist der
Umstand und die Erkenntnis, dass es mit dem Objekt „ego“ einen PKW der Klasse „PKW“
als Funktion der übergeordneten Klasse
„Fahrzeuge“ gibt, der über ein Alleinstellungsmerkmal verfügt, das die
anderen Objekte „vw“ und „bmw“
nicht haben: die beschleunigte Geschwindigkeit in Form des „ego“-Attributs
„a_geschwindigkeit“. Aber es gibt eben nicht nur das Alleinstellungsmerkmal in Form des „ego“-Attributs
„a_geschwindigkeit“, sondern auch zwei
„besondere“ Variablen „a_beschleunigung“ und „a_dauer“ der Klasse
„Fahrzeuge“, die von den anderen
Objekten „vw“ und „bmw“
nicht verwendet werden und demzufolge diesen auch nicht zur
Verfügung stehen! Es gibt also neben den beiden Attribute-Kategorien „statische“ und „dynamische Attribute“ der PKW-Klasse
„vw“ und „bmw“ jetzt auch noch eine weitere Attribute-Kategorie „temporäre Attribute“ der PKW-Klasse „ego“, sozusagen mit Verfallsdatum! Dabei bezieht sich das (Verfalls-) Datum nicht auf
ein zeitlich befristetes Datum wie z.B. jetzt, hier und heute um 20:55 Uhr am
Mittwoch, den 04.12.2019, sondern vielmehr auf eine wie auch immer zeitlich befristete
Existenz eines Attributes! Programmiertechnisch lassen sich also
jederzeit weitere PKW-Klassen wie z.B. die PKW-Klassen „opel“, „psa“
(Peugeot, Citroen), „renault“, „nissan“, „kia“ (Südkoreaner) usw. ohne
existenzielles Verfallsdatum ins bestehende Programm aufnehmen, die
programmiertechnisch nicht besonders sind. Besonders sind hingegen Attribute mit existenziellem
Verfallsdatum,
wie z.B. das „ego“-Attribut „a_geschwindigkeit“, das
programmiertechnisch durch die Konstrukte
„__init()__“, „__str()__“ und „__del()__“ gekennzeichnet ist! - Dabei dienen die beiden Konstrukte „__init()__“ und „__del()__“ ausschließlich dazu, neue, spezielle Variablen einer Klasse
zu generieren, die dann wiederum nur dazu verwendet werden, um spezielle Attribute eines Objektes
z.B. mit existenziellem Verfallsdatum zu definieren: (Zum Vergrößern bitte
auf das Bild klicken!)
Wird demnächst fortgesetzt … … deshalb diese Webseite als Lesezeichen/Favorit
abspeichern! |
||||||
|
[ Home ] [ Seitenanfang ] |
|