|
[ Home ] [ Seitenende ]
|
|
|||||||||
|
Micropython, Teil 2 In den Micropython Grundlagen, Teil
1 “Einleitung
erste Schritte”, Sprachstruktur, interaktive Konsole, wurde das erste
Python-Programm "hallo.py"
programmiert und im YouTube-Video besprochen: (Zum Vergrößern bitte
auf das Bild klicken!) Auch hier im Teil 2 der “Einleitung
erste Schritte”, Sprachstruktur, interaktive Konsole, geht es weiterhin
um das erste Python-Programm "hallo.py",
wenn auch zunächst in abgewandelter Form. Nachfolgend geht es nämlich darum, das
bisherige Programm in eine sogenannte Klasse, engl. „class“, zu
transferieren. Doch zunächst gilt es zu klären, was es mit
einer Klasse auf sicht hat. Nehmen wir zum Beispiel eine große Gesamtschule,
die sich dadurch auszeichnet, dass es an dieser mehrere Schulformen
(Grundschule, Haupt- und Realschule, Gymnasium) gibt. Demzufolge haben große
Gesamtschulen teilweise deutlich mehr als 1.000 Schüler, sodass es an der
Realschule z.B. in einer Jahrgangsstufe gleich mehrere Klassen wie z.B.
Klasse 9a) bis 9d) mit jeweils bis zu 30 Schüler*innen pro Klasse, zusammen
also 120 Schüler der Jahrgangsstufe 9 gibt. Während also der eine oder andere Lehrer als
Deutsch-, Englisch, Physik- oder Mathelehrer in allen Klassen 9a bis 9b
unterrichtet, diese also kennt und z.B. hinsichtlich der schulischen
Leistungen miteinander vergleichen und einschätzen kann, identifizieren sich
die Schüler der Klasse 9a eben nicht mit der Jahrgangsstufe 9 insgesamt,
sondern z.B. eher mit ihren sportlich ambitionierten Mitschülern ihrer Klasse
9a. Während es also in der Klasse 9a überwiegend
ambitionierte Fußballer gibt, gibt es in der Klasse 9b mehr engagierte
Handballer, während sich die Klasse 9d sportlich abgehängt fühlt, sich dafür
aber mehr der Natur verbunden fühlt und in der Klasse 9c gibt etliche
Technikfreaks, die sich gerne mit Computern und Smartphones und deren
Programmierung befassen. Wie man sieht, unterscheiden sich die Klassen
9a bis 9d hinsichtlich der teils spezialisierten Eigenschaften (= Attribute)
und Fähigkeiten (= Methoden) ganz erheblich voneinander. So schwärmt der
Physiklehrer von der technisch interessierten Klasse 9d, während der
Sportlehrer und Fußballfan die sportlichen Fähigkeiten der Klasse 9a
besonders schätzt. Jeder eben so, wie er kann, wie es seiner Sozialisation,
seinen Interessen, Fähigkeiten und Begabungen entspricht. Bei der Fußball ambitionierten Klasse 9a gibt
es wiederum Schüler, die sich als Stürmer in der ersten Reihe bewährt haben,
während andere gerne als Verteidiger in der letzten Reihe spielen und sich
nur ein einziger gerne als Torwart in den Kasten stellt. In diesem Zusammenhang dient also eine Klasse,
engl. „class“, z.B. dazu, junge Menschen mit besonderen sportlichen
Attributen (= Eigenschaften) und fußballerischen Methoden (= Fähigkeiten,
Fertigkeiten) aufzunehmen und diese bezüglich ihrer sportlichen Ambitionen
entsprechend zu fördern. - Nun aber rann an den Speck, erzeugen wir
unsere erste Klasse namens „verwalte_Namensliste“ (siehe Programm „micro_python-hallo_2-1.py“) (Zum Vergrößern bitte
auf das Bild klicken!) Wie man oben im Programm „micro_python-hallo_2-1.py“
sieht, ist die Klasse „verwalte_Namensliste“ noch leer, scheint sich in
dieser nichts zu tun. Aber ist dem wirklich so? Wir wissen es nicht,
weil wir nichts sehen! Aber das lässt sich ja ändern, indem wir in der Klasse
„verwalte_Namensliste“ das „print“-Statement, wie folgt programmieren (siehe
Programm „micro_python-hallo_2-2.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man das Programm „micro_python-hallo_2-2.py“
ausführt, dann staunt der Laie und der Fachmann wundert sich: (Zum Vergrößern bitte
auf das Bild klicken!) Wir setzen noch einen drauf und verschieben die Statements,
d.h. den Programmblock aus dem Hauptprogramm in die Klasse
„verwalte_Namensliste“, (Zum Vergrößern bitte
auf das Bild klicken!) starten das Programm „micro_python-hallo_2-3.py“
und kommen aus dem Staunen nicht heraus, (Zum Vergrößern bitte
auf das Bild klicken!) die Klasse
„verwalte_Namensliste“ startet sich wie von Geisterhand gesteuert ganz von
selbst! Ohne Zutun, ohne dass man die Klasse mittels Statement explizit
starten würde! Wie kann das sein? Ganz einfach, der
Python-Interpreter (= Übersetzer) der „Thonny“-Entwicklungsumgebung
„schaut“ sich nicht nur das (Haupt-) Programm an, sondern auch, ob es im Programm
selbst auch eine oder mehrere Klassen mit Programmkode gibt. Ist dies der Fall, dann
verzweigt der Interpeter in die jeweiligen Klassen und „schaut“ explizit
nach, was sich so in der Klasse tut, d.h. was dort so an Programmkode
programmiert wurde, und ob dieser Auswirkungen in Form von Verknüpfungen,
Verzweigungen, „return“-Ergebnisrückgaben ans (Haupt-) Programm usw. zur
Folge hat. Und, damit es später nicht zu
Programmfehlern, Endlosschleifen, Programmabstürzen oder Einfrieren des
Programms kommt, werden die jeweiligen Klassen beim Programmstart gleich als
Erstes, d.h. noch vor dem eigentlichen Hauptprogramm, gestartet und
ausgeführt! Und zwar mit der konsequenten Folge, dass das im Anschluss
ausgeführte Hauptprogramm sozusagen schon im Vorgriff weiß, was auf es
zukommt bzw. welche „Sauereien“ oder welcher „Spaghetti-Kode“ in der einen
oder anderen Klasse programmiert wurde. Diesbezüglich könnte man auch
sagen, dass die Klassen nebst integrierter Funktionen, die später z.B. vom
(Haupt-) Programm aus aufgerufen und ausgeführt werden, vom Interpreter vorab
auf Widersprüchlichkeiten und Ungereimtheiten untersucht und getestet werden.
In Wirklichkeit ist das Ganze, d.h. das was der Interpreter macht, noch viel
komplexer. - In diesem Zusammenhang stellt
sich dann auch gleich die Frage, ob sich Funktionen innerhalb einer Klasse
auch automatisch, wie von Geisterhand gesteuert, starten. Nehmen wir also die Funktion „einlesen_Vornamen(namens_Liste : list)“ aus
dem Programm „micro_python-hallo_26.py“,
(Zum Vergrößern bitte auf
das Bild klicken!) fügen diese in die Klasse „verwalte_namensliste“ unseres neuen Programms „micro_python-hallo_2-4.py“
wie folgt ein
und starten es, sodass
nachfolgende Bildschirmanzeige erscheint: (Zum Vergrößern bitte auf
das Bild klicken!) Anhand der Bildschirmanzeige
sieht man, dass die · Funktion „einlesen_Vornamen(namens_Liste : list)“ innerhalb der · Klasse „verwalte_namensliste“ eben nicht automatisch
ausgeführt wird! Und das ist gut so, schließlich wollen wir als Programmierer
ja entsprechenden Einfluß auf das Programm nehmen und diese programmiert
steuern. Natürlich auch durch Tastendruck oder Texteingabe seitens des
Anwenders. Da man die Namenliste erst auf dem Bildschirm
anzeigen kann, wenn man sie zuvor mittels der Funktion „einlesen_Vornamen(namens_Liste
: list)“ eingelesen hat, stellt sich die Frage, ob man diese vom Hauptprogramm aus oder von der Klasse „verwalte_namensliste“ aus einliest. Das die Namensliste auf jeden
Fall eingelesen werden muss, sollte man die Einlese-Aktion, d.h. den Aufruf
bzw. das Starten der Funktion „einlesen_Vornamen(namens_Liste)“ in
den Programmkode der Klasse „verwalte_namensliste“ wie
folgt aufnehmen (siehe Programm „micro_python-hallo_2-5.py“):
Schauen wir uns in diesem Zusammenhang
noch die Bildschirmanzeige an, wenn man das Programm „micro_python-hallo_2-5.py“
startet: (Zum Vergrößern bitte
auf das Bild klicken!) Im obenstehenden Screenshot
sieht man, dass die ursprüngliche Namensliste mit den vier Vornamen
innerhalb der Klasse „verwalte_Namensliste“ initialisiert
und mittels der Funktion „einlesen_Vornamen(namens_Liste : list)“ um zwei
weitere Namen erweitert wurde:
Nachfolgend wird die Funktion „einlesen_Vornamen(namens_Liste : list)“ nicht
mehr innerhalb der Klasse „verwalte_Namensliste“
aufgerufen, sondern außerhalb der Klasse
nämlich im Hauptprogramm! Dazu muss man wissen, wie man
eine Funktion, die sich innerhalb
einer Klasse befindet, vom Hauptprogramm aus aufruft, nämlich
durch · den
Namen der Klasse „verwalte_Namensliste“, · gefolgt
von einem Punkt als Bindeglied · zum
Namen der Funktion „einlesen_Vornamen(namens_Liste)“ Das Ganze sieht dann
folgendermaßen aus: · verwalte_Namensliste.einlesen_Vornamen(vornamen_Liste) Damit das dann auch wirklich
funktioniert, brauchen wir noch die namens_Liste =
["Max", "Peter", "Monika", "Petra"], die
sich aber im Programmblock der Klasse „verwalte_Namensliste“
befindet! Dabei stellt sich sogleich
die Frage, wie man vom Hauptprogramm aus an diese herankommt, nämlich durch
die Angabe · des Klassenamens „verwalte_Namensliste“, · gefolgt
von einem Punkt als Bindeglied · und
den Namen „namens_Liste“ Das Ganze sieht dann
folgendermaßen aus: · verwalte_Namensliste.namens_Liste Die Namensliste „namens_Liste“ wiederum
muss aber noch im Hauptprogramm an
die Namensliste „vornamen_Liste“ wie
folgt übergeben werden, · vornamen_Liste = verwalte_Namensliste.namens_Liste damit auch alles wie
gewünscht funktioniert: (Zum Vergrößern bitte
auf das Bild klicken!) Die Bildschirmanzeige des
Programms „micro_python-hallo_2-6.py“
sieht dann folgendermaßen aus: (Zum Vergrößern bitte
auf das Bild klicken!) Das Paradoxe beim Programm „micro_python-hallo_2-6.py“
mit dem Aufruf der Namenanzeige vom Hauptprogramm
aus ist, dass man sich mittels der Funktion
„einlesen_Vornamen(namens_Liste)“ die Namensliste nur ausgeben/anzeigen lassen kann, wenn
man Zugriff auf die Namensliste „namens_Liste“ selbst hat! Und die
wiederum befindet sich zurzeit noch in der Funktion selbst! Da beißt sich also die Katze in den Schwanz,
muss man wissen wie man sich vom Hauptprogramm aus erst mal die Namensliste aus der Funktion holen kann (siehe Bild
oben): · vornamen_Liste = verwalte_Namensliste.namens_Liste Obwohl beim Programm „micro_python-hallo_2-7.py“
der Aufruf der Namenanzeige jetzt vom Hauptprogramm
aus ausgeführt wird, verhält es sich trotzdem noch immer so, dass die Klasse „verwalte_Namensliste“ nach wie vor beim
Programmstart als Erstes ausgeführt wird. Zur Erinnerung an diese wichtige
Erkenntnis, sozusagen in der Hoffnung auf dauerhaft tiefe Verinnerlichung,
dient deshalb die Anzeige
innerhalb der Klasse „verwalte_Namensliste“:
Werfen wir also abschließend
noch einen Blick auf die Bildschirmanzeige des Programms „micro_python-hallo_2-7.py“: (Zum Vergrößern bitte
auf das Bild klicken!) Wir fahren fort und holen als
nächstes · die Funktion „ausgabe_Vornamen()“ aus
dem Programm „micro_python-hallo_26.py“
und fügen sie · der Klasse „verwalte_Namensliste“ im Programm „micro_python-hallo_2-8.py“
wieder hinzu, sodass wir nun
die Namensliste nicht nur ins Programm einlesen, sondern auch wieder
auslesen, indem wir diese auf dem Bildschirm anzeigen. Dabei gilt es zu beachten,
dass wir die Funktion „ausgabe_Vornamen()“ (Zum Vergrößern bitte
auf das Bild klicken!) an das Ende, d.h. hinter
der Funktion 'einlesen_Vornamen()' ins Programm „micro_python-hallo_2-8.py“
einsetzen müssen: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man oben im Programm „micro_python-hallo_2-8.py“
sieht, wird die Funktion „ausgabe_Vornamen()“ vom Hauptprogramm aus aufgerufen.
Demzufolge erfolgt die Programmsteuerung, d.h. das Aufrufen der jeweiligen
Funktion in der funktionalen Reihenfolge, ausschließlich vom Hauptprogramm
aus! Schauen wir uns abschließend noch die
Ausgabe/Anzeige des Programms auf den Bildschirm an: (Zum Vergrößern bitte
auf das Bild klicken!) Nachdem alles so gut geklappt hat, fehlt jetzt
nur noch, dass wir die Funktion „einzelner_Vorname()“ (Zum Vergrößern bitte
auf das Bild klicken!) wieder ins Programm „micro_python-hallo_2-9a.py“,
d.h. in die Klasse „verwalte_Namensliste“ einbauen: (Zum Vergrößern bitte auf
das Bild klicken!) Bei dieser Gelegenheit sollten wir uns noch
einmal in Erinnerung rufen, wie die Funktion
„einzelner_Vorname()“ im Einzelnen
funktioniert: Mit dem Statement · element_Nr_str = input("Welcher Vorname [0 ... " + str(len(hole_vornamenListe) - 1) + "]
soll angezeigt werden ? ") wird der Anwender gefragt, welcher der
angezeigten Namen einzeln angezeigt werden soll, wobei dieser nicht den
Namen selbst, sondern der Einfachheit halber den zugehörigen Index eintasten muss. Bei der Programmierung dieses Statements gilt
es zu beachten, dass der Index der Namensliste generell bei Null beginnt und
bei der Anzahl der Namensfelder ‑ 1 endet: [ 0 … 5 ]. Nach erfolgter Eingabe wird diese dann der Variablen „element_Nr_str“ als String
übergeben. Anschließend wird in den Statements · n = int(element_Nr_str) if
n >= 0 and n <=
len(hole_vornamenListe) - 1: print("Lfd. Nr. = ", n
, "Auslesen/Ausgabe des einzelnen
Vornamens = ", hole_vornamenListe[n]) wiederhole_Eingabe = False else: print("Fehler bei der
Eingabe-Abfrage!\n") wiederhole_Eingabe = True dann mittels der „if“-Abfrage geprüft, ob sich der eingetastete Index „n“
der Namensliste wirklich im Bereich [ 0 … 5 ] befindet oder nicht. Befindet sich der eingetastete Index „n“
im Bereich [ 0 … 5 ], dann bekommt die boolesche Variable „wiederhole_Eingabe“ den Wert „False“ (= „falsch“), sodass die Eingabe später nicht
wiederholt werden muss. Anderenfalls bekommt die boolesche Variable „wiederhole_Eingabe“ den Wert „True“ (= „richtig, zutreffend, ja“), sodass die Eingabe später wiederholt
werden muss: (Zum Vergrößern bitte
auf das Bild klicken!) Die Funktion
„einzelner_Vorname()“ befragt den Anwender
also nur über die „input“-Abfrage, welcher Index
aus dem Bereich [0 ... 5] zu den Vornamen angezeigt werden soll, nicht
aber nach dem Vornamen selbst. Dies hat für den Anwender den Vorteil, dass er
nicht den anzuzeigenden Vornamen selbst eintasten muss, sondern eben nur den
zugehörigen Index. Ferner wird in der Funktion „einzelner_Vorname()“ wider Erwarten nicht
der gewünschte Vorname aus der erweiterten Namensliste „vornamen_Liste“
eingelesen, sondern eben nur der Index.
Der Grund dafür ist der, dass der Anwender aus Versehen oder auch aus Absicht,
um das Programm und die Index-Abfrage zu testen, einen Index außerhalb
des Bereichs [0 ... 5] eintastet, sodass es normalerweise zu einer
entsprechenden Fehlermeldung kommen würde. Mit der „if“-Abfrage innerhalb der
Funktion wird aber genau überprüft, nämlich ob die Index-Abfrage richtig,
d.h. aus dem Bereich [0 ... 5], eingetastet wurde. Ist dies der Fall, dann
wir die boolesche Variable „wiederhole_Eingabe“ auf den Wert
„False“ (= „falsch“) gesetzt
und diese mittels des „return“-Befehls an den Funktionsaufruf · fehlerStatus =
verwalte_Namensliste.einzelner_Vorname(vornamen_Liste) im Hauptprogramm
wieder zurückgegeben. Und im Hauptprogramm wird dann erst in der „while“-Schleife anhand des Variablenwertes „fehlerStatus == True“ entschieden, ob die Index-
bzw. Namensabfrage wiederholt werden muss oder eben nicht. Dabei gilt es zu beachten, dass die
Namensabfrage zwar in der Funktion „einzelner_Vorname()“ erfolgt, nicht
aber deren Wiederholung bei Falscheingabe, da es ansonsten zu einer Endlosschleife innerhalb der
Funktion kommen könnte. Damit genau dies nicht passiert, wird die
Wiederholung der Index-Abfrage für den jeweilig anzuzeigenden Namen außerhalb
der Funktion, nämlich im Hauptprogramm
vorgenommen (siehe Programm „micro_python-hallo_2-9a.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Bis auf den unteren roten Kasten mit der
„while“-Schleife für die wiederholte Eingabe der Indexnummer für den
anzuzeigenden Vornamen (siehe im Bild oben), sieht das Hauptprogramm bisher
recht ordentlich und übersichtlich aus. Damit das so übersichtlich bleibt,
lagern wir den unteren roten Kasten mit der „while“-Schleife einfach in die
darüber befindliche Klasse „verwalte_Namensliste“ aus: (Zum Vergrößern bitte
auf das Bild klicken!) Das obenstehende Programm „micro_python-hallo_2-10.py“
funktioniert aber nur, wenn man die Namensliste
„vornamen_Liste“ ebenfalls mit in die Klasse „verwalte_Namensliste“ übernimmt. Dort muss die Namensliste aber in
„namens_Liste“ wie folgt umbenannt werden: · namens_Liste =
list(["Sven", "Malte", "Lisa",
"Avelina"]) Damit man die beiden Namenslisten bei
der späteren Bildschirmanzeige
besser unterscheiden und verstehen kann, was im Hauptprogramm passiert und was in der Klasse „verwalte_Namensliste“ wurden der Namensliste „namens_Liste“ in der Klasse andere
Vornamen geben: (Zum Vergrößern bitte
auf das Bild klicken!) Hier noch einmal der maßgebliche Quellkode,
engl. source code, zur obenstehenden Bildschirmanzeige (siehe Programm „micro_python-hallo_2-10.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Jetzt sind wir an einem Punkt angekommen, wo
wir uns entscheiden müssen, ob wir die Namensliste im Hauptprogramm nutzen wollen oder in der Klasse „verwalte_Namensliste“ (siehe obenstehendes
Bild). Wegen der guten Übersichtlichkeit des Hauptprogramms und der Option, das
Programm später noch um weitere Funktionen (in einer anderen Klasse) erweitern
zu können, soll die Namensliste im Hauptprogramm verbleiben! Aber nur die
Namensliste, sodass wir die Statements · vornamen_Liste =
verwalte_Namensliste.einlesen_Vornamen(vornamen_Liste) · verwalte_Namensliste.ausgabe_Vornamen(vornamen_Liste) · fehlerStatus =
einzelner_Vorname(namens_Liste) später aus dem Hauptprogramm des Programms „micro_python-hallo_2-11.py“
auslagern. Es ist zwar recht praktisch, wenn die Klasse „verwalte_Namensliste“ nebst Anzeige der Namensliste noch vor
der Ausführung des Hauptprogramms
gestartet wird, trotzdem ist aber besser, wenn sich die Ausgabe/Anzeige der Namensliste „vornamen_Liste“ erst auf spezielle
Veranlassung hin starten lässt. Aus diesem Grund wird die Ausgabe/Anzeige der
Namensliste in die Funktion „anzeigen_Namensliste“ aus dem Hauptprogramm
ausgelagert (siehe Programm „micro_python-hallo_2-12.py“).
Dabei bietet die Funktion „anzeigen_Namensliste“ gegenüber der
gekapselten Klasse „verwalte_Namensliste“ den Vorteil, dass sie
sich von überall her jederzeit einfacher aufrufen und ausführen lässt: (Zum Vergrößern bitte auf
das Bild klicken!) Es gibt zwei Sprichworte: a) „Wer Ordnung hält
ist nur zu faul zu suchen.“ und b) „I d’ont like the chaos, but the chaos
likes met!“, d.h. „Ich missbillige das Chaos, aber das Chaos mag mich!“ Man
könnte auch sagen: „Vorsicht ist die Mutter der Porzellankiste!“ Sei es wie es ist, wir halten Ordnung und
verlagern die Funktion „anzeigen_Namensliste()“ in die Klasse „verwalte_Namensliste“, da wir später noch ein kleines Auswahlmenü programmieren
werden, mittels dem man gezielt bestimmte Funktionen auswählen und aufrufen
kann. Und dazu ist es hilfreich, wenn diese alle an einem Ort, d.h. in einer
Klasse stehen. Nachträgliches
Korrigieren bzw. Ändern eines Namens Als Nächstes haben wir uns eine kleine
Abwechselung verdient, indem wir das bisherige Namens-Programm erweitern. Und
zwar um die Funktion der nachträglichen Namensänderung. Dazu müssen
wir uns mittels der Funktion „einzelner_Vorname(vornamen_Liste)“ nur den gewünschten
Vornamen anzeigen lassen und diesen mittels eines weiteren „input“-Befehls namentlich abändern: (Zum Vergrößern bitte
auf das Bild klicken!) Beim Programm „micro_python-hallo_2-13.py“
und der neu hinzugefügten Funktion „korrigieren_Vorname()“ fällt auf, dass wir
diese aus Gründen des logischen Sinnzusammenhangs vor die Funktion
„anzeigen_Namensliste()“ positioniert haben, damit sichergestellt ist, dass die
nachfolgende Funktion „anzeigen_Namensliste()“ später auch
tatsächlich auf die zuvor geänderte Namensliste zugreifen kann. Im Zusammenhang mit der Funktion „korrigieren_Vorname()“ entsteht nun
vielleicht der Wunsch, dass man einen weiteren Datensatz (= Vornamen)
der bisherigen Namensliste hinzufügen will. Wie man sich denken kann,
ist das nicht weiter schwierig, muss man doch nur den hinzuzufügenden
Vornamen eingeben und an die bestehende Datenbank (= Liste mit den Vornamen)
wie folgt anfügen: (Zum Vergrößern bitte
auf das Bild klicken!) Damit sich das Programm „micro_python-hallo_2-14.py“
und die neu hinzugefügte Funktion „anhaengen_Vorname()“ vom Hauptprogramm aus aufrufen lässt, müssen
wir in diesem noch das Statement 1.
verwalte_Namensliste.anhaengen_Vorname(vornamen_Liste) hinzufügen: (Zum Vergrößern bitte auf
das Bild klicken!) Wie man im obenstehenden Sourcecode sieht,
wurde der Funktionsaufruf „korrigieren_Vorname(vornamen_Liste)“
im Programm „micro_python-hallo_2-14.py“
vorübergehend „auskommentiert“, d.h. deaktiviert, damit das Hauptprogramm, indem ja ansonsten
stets alle Funktionen der Reihe aufgerufen werden, übersichtlich bleibt. Werfen wir abschließend noch einen Blick auf
die Anzeige/Ausgabe des Bildschirms, um zu sehen, dass auch alles tatsächlich
wie gewünscht, d.h. programmiert, funktioniert: (Zum Vergrößern bitte
auf das Bild klicken!) Nachfolgend geht es im Programm „micro_python-hallo_2-15.py“
darum, dass wir an einer beliebigen Stelle der Namensliste „vornamen_Liste“ einen weiteren
Datensatz, d.h. einen neuen Vornamen in die bestehende Namensliste einfügen,
sodass diese sich um einen Datensatz entsprechend vergrößert. Diesbezüglich
wenden wir einen kleinen Trick an, der aber ganz einfach ist. Und zwar
arbeiten wir mit drei Datenbanken (= Namenslisten) als da sind a) die alte Namensliste „vornamen_Liste“, b)
die temporäre Namensliste
„temp_vornamenListe“ mit der wir konkret
arbeiten und c)
die neue Namensliste
„neue_vornamenListe“, die sich abschließend aus
der alten plus der temporären Namensliste zusammensetzt. Bei der Programmierung des Programm „micro_python-hallo_2-15.py“
benutzen wir zunächst die alte Namensliste
„vornamen_Liste“ und fragen mittels
des „input“-Befehls ab, an welcher Position der Datenbank der neue Name
eingefügt werden soll: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Screenshot (=
Schnappschuss vom Bildschirm) sieht, wird der Inhalt des ausgewählten, indexierten
Datensatzes (= Vorname) zunächst nur angezeigt (siehe grüner
Kasten),
damit der Anwender weiß, an welcher Position er anschließend einen
neuen, d.h. weiteren/zusätzlichen Namen eintasten/anlegen kann: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Bild sieht, wird der
aktuell ausgewählte Datensatz mit dem Index = 3 und dem Namen „Petra“ nicht
einfach von der neuen Namenseingabe „Heinz“ überschrieben, sondern an letzter
Position der Datenbank angefügt, sodass die „Petra“ eben nicht
überschrieben, d.h. gelöscht wird, sondern erhalten bleibt. An letzter Stelle
der Datenbank bedeutet dabei aber nicht, dass es sich bei der Petra um das
Letzte handelt, sondern um die Letzte am neuen Ende der erweiterten Datenbank
;-) Programmiertechnisch und logisch bedeutet
dies, dass wir die alte Datenbank bis zur Index-Position [ 0 ... 2 ]
(= 3 Datensätze) verwenden, d.h. unverändert beibehalten, temp_vornamenListe
= list() temp_vornamenListe
+= hole_vornamenListe dann beim 4. Datensatz mit dem Index = 3 den neuen Vornamen „Heinz“ hinzufügen, temp_vornamenListe[n] = str(hinzufuegen_Vorname) indem der Dateninhalt „Petra“ mit „Heinz“
überschrieben wird. Anschließend wird die neue Datenbank
„neue_vornamenListe“ generiert und dieser der Inhalt der alten
Datenbank „hole_vornamenListe“ plus neuer Vornamen „Heinz“ übergeben (= 4
Datensätze mit dem Index [ 0 … 3 ]): neue_vornamenListe
= list() neue_vornamenListe
+= temp_vornamenListe Abschließend wird der übrig gebliebene
Datenbankinhalt „Petra“ aus der alten Datenbank „hole_vornamenListe“ geholt
und der neuen wie folgt hinzugefügt (= 5 Datensätze mit dem Index [ 0 … 3 ]): neue_vornamenListe
= neue_vornamenListe + [hole_vornamenListe[PosNr]] Wie man im Programm „micro_python-hallo_2-15.py“
anhand des Sourcecodes sieht, ist die Programmierung, d.h. der Umgang mit
drei Datenbanken (neue Datenbank = alte Datenbank bis Indexpos. 2 + Name an
der Indexpos. 3 + Rest der alten Datenbank an der neuen Indexpos. 5) gar
nicht so schwer: (Zum Vergrößern bitte auf
das Bild klicken!) Das Bemerkenswerte bei der obenstehenden
Programmierung ist der Umstand, dass wir ganz ohne „for“- oder
„while“-Schleifen sowie der Umschichtung von Datensätzen in den Datenbanken
ausgekommen sind. Damit das Hauptprogramm mit seinen vielen
Funktionen noch übersichtlich bleibt und sich dieses auch komfortabel
bedienen lässt, programmieren im Programm „micro_python-hallo_2-16.py“
noch eine entsprechende Menüauswahl mit der sich alle
Funktionen je nach Bedarf einzeln
aufrufen lassen: (Zum Vergrößern bitte auf
das Bild klicken!) Werfen wir bei dieser Gelegenheit noch einen
Blick auf die Menüauswahl, so wie sie sich auf
dem Desktop des Windows-PCs darstellt, wenn man das Programm „micro_python-hallo_2-16.py“
in der „Thonny“-Entwicklungsumgebung startet: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn man das Programm startet und mittels der Menüauswahl mehr und mehr Funktionen
ausprobiert, dann stellt man unschwer fest, dass die Menüauswahl im Fenster „Thonny Shell“ der „Thonny“-Entwicklungsumgebung nach oben aus dem
Blickfeld bzw. dem Fensterausschnitt wandert, sodass man notgedrungen in der
Shell nach oben scrollen muss, um wieder die Menüauswahl zu sehen und nachzuschlagen. Wenn man dann mittels der Menüauswahl (6)
wieder das Programm „micro_python-hallo_2-16.py“
verlassen will, dann muss man in der Shell wieder ganz nach unten
scrollen bis die Eingabezeile „Treffen Sie jetzt Ihre Menüauswahl:“ erscheint, um dann
die „6“ zum Verlassen des Programms eintasten zu können. Das ist natürlich
alles andere als anwenderfreundlich und ergonomisch. Aus diesem Grund werden wir als Nächstes die
Menüauswahl (siehe im Bild oben) in eine eigene Funktion einer anderen Klasse
auslagern und dabei den Menüaufruf
selbst jederzeit per Tasteneingabe
„m“ wiederholt zur
Anzeige auf den Bildschirm bringen. - Wenn man das bisherige Menü und dessen Menüauswahlen,
wie zuvor beschrieben, komfortabeler und ergonomischer gestalten, d.h. programmieren
will, dann muss man dieses so programmieren, dass sich das Menü sozusagen auf
Knopfdruck jederzeit erneut und beliebig oft aufrufen bzw. starten lässt. Wenn sich aber bestimmte Dinge immer
wiederholen, wiederholen lassen, wiederholen lassen sollen oder müssen, dann
braucht es im einfachsten Falle eine „for“- oder „while“-Schleife. Wenn aber das Ganze
komplexer ist, dann muss man eine Funktion programmieren, die
sich ähnlich einer „Endlos“-Schleife jederzeit und beliebig oft aufrufen und wiederholen
lässt. Schauen wir uns also den betreffenden
Quellkode der Menüsteuerung noch einmal an, bevor
wir uns klar darüber werden, ob sich der gesamte Quellkode oder nur
Teile davon in eine separate Funktion auslagern lassen oder
nicht: (Zum Vergrößern bitte
auf das Bild klicken!) Diesbezüglich stellt sich die Frage, wie eine Menüsteuerung prinzipiell funktioniert und aus
welchen Teilen sie sich zusammensetzt, als da wären: 1. Liste „auswaehlen_Menue“ mit auswählbaren
Menüfunktionen, 2.
Anzeige „print()“ der auswählbaren Menüfunktionen, 3.
Abfrage „while“ mit Prüfung,
welche Menüfunktion ausgewählt wurde, 4.
Namensliste „vornamen_Liste“, die mittels ausgewählter
Menüfunktion bearbeitet werden soll. Bei der Namensliste
„vornamen_Liste“, die später einmal in
einer Datei gespeichert und von
dort aus auch wieder eingelesen werden soll, stellte sich deshalb die Frage,
wo man diese zweckmäßiger Weise im Programm bearbeitet: a) im Hauptprogramm oder b) innerhalb der Klasse „verwalte_Namensliste“. Wenn man die Namensliste „vornamen_Liste“ innerhalb der Klasse „verwalte_Namensliste“ verwaltet und bearbeitet, dann hat dies den
Vorteil, dass alle in der Klasse
enthaltenen Funktionen, quasi wie
bei einer globalen Variablen, problemlos auf diese zugreifen können. Aber wo es Sonne gibt, gibt es auch Schatten,
nämlich die Sorge, dass, wenn man die Namensliste innerhalb der Klasse
bearbeitet, diese früher oder später unbeabsichtigt „zerschossen“
wird, indem man mit dieser arbeitet und dabei diese dann auch verändert,
indem man z.B. Namen aus der Liste löscht oder welche hinzufügt, sodass die ursprüngliche
Original-Namensliste für die spätere,
nachträgliche Bearbeitung nicht mehr in ihrem Ursprung zur Verfügung steht! Aus diesem Grund
empfiehlt es sich unbedingt, stets nur mit einer Kopie
der Namensdatei zu arbeiten und
eben nicht dem Original! Damit sich die (Original-) Namensliste „vornamen_Liste“ später im Quellkode
sofort finden lässt und nicht umständlich innerhalb der Klasse und den
Funktionen gesucht werden muss, wurde diese ins Hauptprogramm aufgenommen. Unter anderem auch aus dem Grund, weil die Namensliste später noch bearbeitet,
d.h. in einer Datei gespeichert werden
soll. Dazu braucht es dann weitere Funktionen,
wie z.B. das Laden, Lesen, Schreiben oder Erweitern einer Datei, die wiederum
alle in einer gemeinsamen Klasse „Dateioperationen“ zusammengefasst
werden! Kurz und knapp, das Arbeiten mit Klassen und den darin enthaltenen Funktionen macht Sinn, lassen sich
doch programmiertechnisch und thematisch zusammenhängende Sachverhalte in
Form von Funktionen innerhalb
einer Klasse zusammenfassen und
deren Variablen nebst (Variablen-) Inhalten auf den lokalen Zugriff innerhalb
einer Funktion beschränken. Dabei
erfolgt der Zugriff auf Daten von Variablen innerhalb einer Funktion hauptsächlich durch den Funktionskopf und/oder über das Statement „return“ bzw. „return()“ für die entsprechende Rückgabe an die Klasse
oder das Hauptprogramm. Je nachdem
von wo aus die Funktion aufgerufen wurde. Innerhalb einer Klasse können Funktionen
mit anderen Funktionen miteinander
und untereinander kommunizieren und Daten
in Form von Variableninhalten austauschen, indem
sie dazu ein- und dieselbe Variable verwenden, die dabei
aber wiederum in der gemeinsamen Klasse
deklariert, initialisiert oder einfach nur benutzt werden muss. Innerhalb einer Klasse lassen sich Funktionen der eigenen
Klasse durch Aufruf des Funktionsnamens nebst eventueller
Übergabe von Parametern im Funktionskopf starten und
ausführen: · Statement „einlesen_Vornamen(vornamen_Liste)“ Dabei lassen sich im Funktionskopf auch neue Variable deklarieren, die wiederum innerhalb
der gesamten Funktion gültig sind! Wenn man eine Funktion
von außerhalb der Klasse, z.B. vom Hauptprogramm aus, aufrufen will,
dann muss man dem Funktionsnamen den Klassennamen, in dem sich Funktion
befindet, wie folgt voranstellen: · Statement „verwalte_Namensliste.einlesen_Vornamen(vornamen_Liste)“ Ähnlich verhält es sich, wenn man Variablen und Variableninhalte einer Klasse
von außerhalb der Klasse, wie z.B. aus dem Hauptprogramm heraus, ansprechen und nutzen will. Diesbezüglich
lassen sich Variablen und deren Variableninhalte einer Klasse von außerhalb der Klasse durch Aufruf des Klassennamens gefolgt vom Variablennamen wie folgt verwenden: · Statement „verwalte_Namensliste.vornamen_Liste“ Beim Programm „micro_python-hallo_2-16.py“
nutzen wir alle die soeben besprochenen Möglichkeiten wie z.B. das Aufrufen
von Funktionen aus dem Hauptprogramm heraus (siehe
Menüverwaltung) und das Übertragen der Variableninhalte
„vornamen_Liste“ an die jeweiligen Funktionen (siehe Menüauswahl). Und trotzdem hat
das Programm „micro_python-hallo_2-16.py“
noch einen erheblichen „Schönheitsfehler“, der das ordnungsgemäße
Funktionieren des Programms unmöglich macht. Zwar ist es uns gelungen, die Namensliste „vornamen_Liste“ vom Hauptprogramm aus im Funktionskopf an verschiedene Funktionen (siehe Menüauswahl) zu übergeben, d.h.
zu transferieren. Wider Erwarten ist es uns aber bisher noch nicht
gelungen, die um den Vornamen „Petrus“ erweiterte Namensliste „vornamen_Liste“ wieder an das Hauptprogramm zurückzugeben: (Zum Vergrößern bitte
auf das Bild klicken!) In Funktionen mittels „self“-Statement
auf Klassenvariablen zugreifen Für das im obenstehenden Bild beschriebene
Manko, dass sich die erweiterte Namensliste
„vornamen_Liste“ wider Erwarten bisher
nicht wieder an das Hauptprogramm
zurückgeben lässt, gibt es aber einen einfachen Grund! Nämlich den, dass wir
bisher noch nicht wirklich wissen, wie man Variableninhalte aus dem Hauptprogramm
an die Klasse „verwalte_Namensliste“ und somit auch an
alle in der Klasse enthaltenen Funktionen transferieren kann! Mit dem Programm „micro_python-hallo_2-17.py“
aber ist das beschriebene Manko endgültig behoben! Probieren Sie es aus, und
finden Sie heraus, wie der Nachteil, dass sich die namentlich erweiterte
Namensliste „vornamen_Liste“ wider Erwarten bisher
nicht wieder ans Hauptprogramm
oder an andere Funktionen der Klasse „verwalte_Namensliste“ zurückgeben ließ, behoben wurde! Nachfolgend geht es darum, den Zugriff auf die
(Klassen-) Variable „klassen_Var“ innerhalb der Klasse „verwalte_Namensliste“ als auch auf die (Funktions-) Variable „funktions_Var“ innerhalb der Funktion „einlesen_Vornamen()“ zu bewerkstelligen (siehe Programm „micro_python-hallo_2-18.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Wie man anhand des Programm „micro_python-hallo_2-19.py“
sieht, (Zum Vergrößern bitte
auf das Bild klicken!) kommt man vom Hauptprogramm aus nur an den Variableninhalt der Variablen
„funktions_Var“ mittels des Statements „return(funktions_Var)“. Dies gelingt aber
nur, wenn man vom Hauptprogramm
aus die Funktion „einlesen_Vornamen()“ aufruft! Wie man anhand des Programm „micro_python-hallo_2-20.py“
sieht, (Zum Vergrößern bitte
auf das Bild klicken!) lässt sich die Funktion „einlesen_Vornamen()“ auch aus der Klasse „verwalte_Namensliste“ heraus aufrufen und ausführen. Auf die Variable „export_funktions_Var“ lässt sich dann vom Hauptprogramm aus mittels des Statements „verwalte_Namensliste.export_funktions_Var“ zugreifen. – Wie man anhand des Programms „micro_python-hallo_2-21.py“
sieht, (Zum Vergrößern bitte
auf das Bild klicken!) lässt sich der Variableninhalt „Ich bin die
Funktionsvariable 'funktions_Var'“ der Variablen
„funktions_Var“ in der Funktion „einlesen_Vornamen(self)“ auch ganz ohne Statement „return
In diesem Zusammenhang könnte man nun auf die
Idee kommen und sagen, dass man innerhalb der Funktion „einlesen_Vornamen(self)“
anstelle des · Statements „self.export_funktions_Var = funktions_Var“ gleich das · Statement „verwalte_Namensliste.export_funktions_Var = funktions_Var“ verwendet, um sich auf diese Weise den ganzen „self“-Kladderadatsch zu ersparen. Aber
genau das geht so leider nicht, weil der Klassennamen „verwalte_Namensliste“ der Funktion „einlesen_Vornamen()“ nicht bekannt ist, sondern erst durch
den Funktionsaufruf „einlesen_Vornamen(self)“
noch bekannt gemacht werden muss. Mit anderen Worten: die Funktion „einlesen_Vornamen()“ weiß von sich aus gar nicht, dass es eine Klasse „verwalte_Namensliste“ gibt; deshalb der „Umweg“ über „self“ im Funktionsaufruf
„einlesen_Vornamen(self)“.
- Jetzt wo im Programm „micro_python-hallo_2-21.py“
die neue Klassenvariable „export_funktions_Var“ in der Funktion „einlesen_Vornamen(self)“ mittels des · Statement „self.export_funktions_Var = funktions_Var“ initialisiert wurde, kann man die
vorausgegangene Initialisierung
innerhalb der Klassen „verwalte_Namensliste“ mittels des · Statements „export_funktions_Var = ‚Ich
bin die NEUE Export-Funktionsvariable!’“ verzichten
und diese im Programm „micro_python-hallo_2-22.py“
mittels „#“ auskommentieren, d.h.
deaktivieren: (Zum Vergrößern bitte
auf das Bild klicken!) Mit
dem Programm „micro_python-hallo_2-23.py“
(Zum Vergrößern bitte
auf das Bild klicken!) lässt sich zeigen, dass sich die neue Klassenvariable „export_funktions_Var“ tatsächlich auch in
der Funktion „einlesen_Vornamen(self)“
nutzen und deren Variableninhalt „Das HAUPTPROGRAMM(!) initialisiert NEUE
Klassenvariable!“
mittels des Statements „return(self.export_funktions_Var)“ wieder an das Hauptprogramm zurückgeben lässt: (Zum Vergrößern bitte
auf das Bild klicken!) Jetzt
können wir das neu erworbene Wissen über das Initiieren von globalen Klassen-
oder Funktionsvariablen, die sich quer über alle Funktionen und Klassen
nutzen lassen, konkret anwenden. Zu diesem Zweck greifen wir wieder das Programm „micro_python-hallo_2-17.py“ auf, verbessern es im ersten Schritt bei der Funktion „starte_Menueauswahl()“, indem wir die Funktion auf das Anwenden der „self“-Variable wie folgt umstellen: (Zum Vergrößern bitte
auf das Bild klicken!) Leider verhält es sich bei dem im Bild
obenstehenden Quellkode der Funktion „starte_Menueauswahl(self)“
so, dass sich das „self“-Statement wider Erwarten nicht auf die Tabelle „auswaehlen_Menu = ( … )“ anwenden lässt, da das Statement „exec(auswaehlen_Menue[lfdNr_Menue])“ das „self“-Statement nicht auflösen kann. Wie man aber anhand des · Statements „self.einlesen_Vornamen(self.vornamen_Liste)“ sieht, lassen sich die Menüfunktionen trotzdem jederzeit auf konventionelle
Weise mittels „self“-Statement aufrufen und ausführen. Was noch erwähnt werden muss, ist, dass die (Menü-) Funktion „starte_Menueauswahl(self)“ zwischenzeitlich in
die eigene Klasse „verwalte_Menueauswahl“ aufgenommen wurde,
sodass Menüorganisation und Verwaltung funktionell von der Klasse „verwalte_Namensliste“ strikt getrennt sind. Achtung: Beim Programm „micro_python-hallo_2-24.py“
wurde das „self“-Statement jetzt der Klasse „verwalte_Menueauswahl“ zugewiesen! - Datentransfer mittels „self“-Statement
von Klasse 1 zu Klasse 2 Um den Umgang und die Handhabung mit dem „self“-Statement noch besser zu
verstehen und anwenden zu können, schauen wir uns das Programm „micro_python-hallo_2-25.py“
genauer an: (Zum Vergrößern bitte
auf das Bild klicken!) Wie aber funktioniert das obenstehende
Programm „micro_python-hallo_2-25.py“?
In der Funktion
„Funktion_1“ wird die Textstringvariable „TextStrVar_1“ initialisiert und diese über das Statement „self“
der Klasse „Klasse_1“ zugewiesen. Damit das dann auch
funktioniert, muss im Hauptprogramm
der Variablen „self“ der Klassenname
„Klasse_1“ zugewiesen werden!
Auf diese Weise wird die Funktion „Funktion_1“ zum Sender, d.h. zur Quelle, engl. source“, während gleich die Funktion „Funktion_2“ zum Empfänger,
d.h. zur Senke, engl. sink“ wird. In der Funktion
„Funktion_2“ soll die Textstringvariable „TextStrVar_1“ den Variableninhalt der Klassenvariablen „self.TextStrVar_1“ der Klasse „Klasse_1“ entgegennehmen. Damit das auch funktioniert, muss der lokalen(!)
Textstringvariable „TextStrVar_1“ der Funktion „Funktion_2“(!) noch die Variable „self“
vorangestellt werden, damit diese ebenfalls, wie die bereits bestehende,
globale(!) Klassenvariablen „self.TextStrVar_1“ der Funktion „Funktion_1“ (= Sender), zur globalen(!) Klassenvariablen „self.TextStrVar_1“ der Funktion „Funktion_2“(!) (= Empfänger) wird und auf den
Variableninhalt derselben zugreifen kann. Anschließend lässt sich dann der
Variableninhalt der globalen(!) Klassenvariablen
„self.TextStrVar_1“ der Klasse „Klasse_1“ in der Funktion „Funktion_2“(!) mittels des „print“-Statements anzeigen.
Die Klassenvariable
„self.TextStrVar_1“ (= Empfänger) in der Funktion
„Funktion_2“ der Klasse „Klasse_2“ kann aber erst dann den Variableninhalt der anderen Klassenvariable „self.TextStrVar_1“ (= Sender) in der Funktion „Funktion_1“ der Klasse „Klasse_1“ entgegennehmen und mittels des „print“-Statements anzeigen, wenn im Hauptprogramm das Statement „Klasse_2.Funktion_2(Klasse_1)“ ausgeführt wird: Statement „Klasse_1.Funktion_1(Klasse_1)“
→ Statement „Klasse_2.Funktion_2(Klasse_1)“
Da man aber zu Zwecken des besseren
Verständnisses und zur Vermeidung von Verwechselungsgefahren - man sieht den beiden
Briefkästen gleichen Namens nicht an, dass der eine Bewohner
Müller im Ergeschoß und die andere Bewohnerin Müller im 5. Stock
wohnt - namensgleiche Variablennamen tunlichst vermeiden soll,
verwenden wir im Programm „micro_python-hallo_2-26.py“
unterschiedliche Variablennamen mit dem Vorteil, dass sich das Programm dabei auch
noch besser verstehen lässt: (Zum Vergrößern bitte
auf das Bild klicken!) Jetzt drängt sich gleich noch die Frage auf,
ob sich der „self“-Datentransfer auch in die umgekehrte Richtung, d.h.
rückwärts vornehmen lässt (sieh Programm „micro_python-hallo_2-27.py“): (Zum Vergrößern bitte
auf das Bild klicken!) Wie man anhand der roten Richtungspfeile im
obenstehenden Bild sieht, lässt sich der Datentransfer zwischen den
Funktionen auch rückwärts, d.h. von unten nach oben vornehmen.
Ungewohnt beim Lesen des Quellkodes ist dabei, dass man diesen jetzt auch rückwärts
von unten nach oben lesen muss, um das Ganze auch zu verstehen. Schließlich geht es beim Datentransfer darum, dass wir diesen von Funktion 2 zur
Klasse 2 und dann weiter nach
oben zur Klasse 1 und von dort aus zur Funktion 1 durchführen, wobei die Lesart des Quellkodes von unten nach oben
ungewohnt erscheint (siehe Programm „micro_python-hallo_2-27.py“).
Damit sich keine Fehler einschleichen, sollten wir die Lesart des Quellkodes von oben nach unten
beibehalten und zu diesem Zweck die beiden Klassen
nebst Funktionen wie folgt vertauschen: (Zum Vergrößern bitte
auf das Bild klicken!) Wenn wir bei der Programmierung des Quellkodes und der gewohnten Lesart von oben nach unten
bleiben, dann fällt auf, das der Datenaustausch zwischen der Variablen „self.SendeVar“ und „self.EmpfangsVar“ stets in der unteren Klasse bzw.
Funktion erfolgt, was ja auch logisch ist (siehe Programm „micro_python-hallo_2-28.py“).
– Wie man anhand des Quellkodes im obenstehenden
Bild sieht, bewirkt das Statement „Klasse_2.Funktion_2(Klasse_1)“ im Hauptprogramm,
dass die Funktion „Funktion _2“ zusammen mit dem Parameter „Klasse_1“ aufgerufen wird und
dabei der Parameter „Klasse_1“ an die Stringvariable „self“ im Funktionskopf übergeben wird. Da wir
aber im Programm „micro_python-hallo_2-29.py“
in der Funktion „Funktion _2“ das · Statement „self.SendeVar = ‚Ich bin Text aus der Funktion 2!’“ auf das · Statement „Klasse_1.SendeVar = ‚Ich bin Text aus der Funktion 2!’“ abgeändert haben, machen wir vom „self“-Parameter im Funktionskopf keinen Gebrauch. Und siehe da,
das Programm funktioniert trotzdem in der gewohnten Weise, (Zum Vergrößern bitte
auf das Bild klicken!) gibt keine Abweichung beim Ergebnis
bzw. der Anzeige auf dem Bildschirm. - Da wir in der Funktion „Funktion
_2“
von dem „self“-Parameter keinen Gebrauch mehr machen, können
wir dieses auch weglassen, sodass sich auch der Funktionsaufruf der Funktion „Funktion _2“ aus dem Hauptprogramm
heraus entsprechend vereinfacht (siehe Programm „micro_python-hallo_2-30.py“):
· Statement „Klasse_2.Funktion_2()“ In der Funktion
„Funktion _1(self)“
der Klasse „Klasse_1“ benutzen wir zwar noch den „self“-Parameter im · Statement „print("Inhalt
der Variablen 'SendeVar' = ", self.EmpfangsVar,
"\n")“,
bräuchten das aber eigentlich nicht mehr, da
die Klassenvariable „self.EmpfangsVar“ gleichbedeutend ist mit der Klassenvariablen „Klasse_1.EmpfangsVar“: (Zum Vergrößern bitte
auf das Bild klicken!) Im Programm „micro_python-hallo_2-31.py“
verzichten wir erstmals auf alle „self“-Parameter, (Zum Vergrößern bitte
auf das Bild klicken!) ohne dass sich irgendeine Fehlfunktion, ein Fehler
oder fehlerhafte Anzeige einstellen würden! – Wenn wir z.B. den Variableninhalt einer
lokalen Variablen oder den Textstring „Ich bin Text aus der Funktion 2!“ innerhalb der Funktion „Funktion_2()“ nach außen, d.h. im Hauptprogramm
oder in der Funktion „Funktion_1()“, verfügbar machen wollen, dann musste
bisher stets ein Aufruf der Funktion über die zugehörige Klasse im Hauptprogramm veranlasst werden
(siehe Quellkode im obenstehenden Bild). Dabei ist der Grund dafür der, dass Funktionen innerhalb einer Klasse ziemlich stringent gekapselt sind.
Und, wenn man auf Variableninhalte einer Funktion zugreifen will und dieser
dabei stets direkt oder indirekt über das Hauptprogramm veranlasst werden muss, dann ist das Hauptprogramm stets involviert, ist
dieses quasi auf den Variablenzugriff einer lokalen Variablen einer Funktion informiert! Wie wir aber gleich sehen werden, geht es auch
ohne den Umweg über das Hauptprogramm,
lassen sich Variableninhalte auch direkt von
Funktion zu Funktion übertragen und zugänglich machen! Zu diesem
Zweck müssen wir uns an eine Eigenart
von Klassen erinnern: Klassen mit oder ohne Funktion, werden beim Programmstart noch vor dem Abarbeiten von Quellkode des Hauptprogramms aufgerufen
und ausgeführt!
Macht man sich diese Eigenart von Klassen zunutze, dann kann
man aus der Klasse heraus auch die darin
befindliche Funktion starten und den Inhalt einer lokalen Funktionsvariablen mittels „return“-Statement an die jeweilige Klasse übertragen, sodass dieser mittels der Klassenvariablen von überall her
verfügbar ist. Auch und gerade durch eine weitere Funktion einer weiteren
Klasse (siehe Programm „micro_python-hallo_2-32.py“):
(Zum Vergrößern bitte
auf das Bild klicken!) Selbstverständlich lässt sich der im Bild obenstehende
Sourcecode auch noch kürzer, d.h. kompakter programmieren (siehe Programm „micro_python-hallo_2-33.py“):
(Zum Vergrößern bitte
auf das Bild klicken!) Wie man im obenstehenden Quellkode sieht, kann
man sich in der Funktion „Funktion_2()“ den Textstring „Ich bin
Text aus der Funktion 2!“ mittels des „return“-Statements zurückliefern lassen. Und zwar an die Klassenvariable „SendeVar“ der Klasse „Klasse_2“. Zu diesem Zweck muss
man aber im · Statement „SendeVar =
Funktion_2()“ zunächst die Funktion „Funktion_2()“ aufrufen und den
mittels „return“-Statement zurück gelieferten Textstring der Klassenvariablen „SendeVar“ zu weisen (siehe
roter Kasten im obenstehenden Quellkode bei der „Funktion_2“)!
Wenn man das weiß, dann kann man, wie im
Programm „micro_python-hallo_2-34.py“
gezeigt, auch ganz auf die beiden Funktionen
„Funktion_2“ und „Funktion_1“ verzichten: (Zum Vergrößern bitte
auf das Bild klicken!) Autostart von Klassen und Steuerung von Klassen durch
Funktionen So, jetzt sind wir wieder da angekommen, von
wo aus wir im Prinzip gestartet sind. Allerdings mit einem Unterschied, dass
wir wieder eine ganze Menge gelernt haben. Aber bekanntlich lernt man ja nie
aus, gibt es immer wieder etwas Neues zu entdecken und auszuprobieren. Zurück zu den Wurzeln und zwar zum Programm „micro_python-hallo_2-35.py“
bei dem wir es mit den beiden Klassen „Klasse_1“ und „Klasse_2“ zu tun haben, wobei beide Klassen mit Programmcode zwecks
Anzeige von Variableninhalten ausgestattet sind. Das Interessante am Programm
„micro_python-hallo_2-35.py“ ist dabei, (Zum Vergrößern bitte
auf das Bild klicken!) dass mit dem Programmstart beide Klassen
„Klasse_1“ und „Klasse_2“ mit samt dem Programmkode der Reihe
nach ausgeführt werden. Und zwar ohne dass es irgendeines Aufrufs
aus dem Hauptprogramm bedarf. Mal
abgesehen davon, dass das im Moment auch gar nicht funktionieren
würde, weil sich Klassen per se nicht
aufrufen und ausführen lassen. Außer mit einem kleinen Trick, wie wir gleich
noch sehen werden. Interessant ist am Programm „micro_python-hallo_2-35.py“
auch noch, dass wir sozusagen von außen nicht so ohne Weiteres an den Variableninhalt der lokalen Variablen „lokale_SendeVar“ in der Funktion
„Funktion_1()“ herankommen! Es sei
denn, dass wir diese an die Klasse „Klasse_1“ übergeben, indem wir die Funktion „Funktion_1()“ aufrufen und den Wert der lokalen (Funktions-) Variablen „lokale_SendeVar“ an die (Klassen-) Variable „SendeVar“ übertragen (siehe obenstehendes Bild).
- Im Programm
„micro_python-hallo_2-36.py“
geht es bei der Klasse „Klasse_1“ darum, diese jederzeit
aufrufbar und ausführbar zu machen. Zu diesem Zweck wird die Klasse „Klasse_1“ in die äußere Funktion
„anzeigen_Klasse_1()“ verfrachtet, d.h.
verschoben, wodurch die Klasse ihre bisherige selbststartende
Eigenschaft beim Programmstart verliert! Um die bisherige selbststartende
Eigenschaft der Klasse „Klasse_1“ beim Programmstart wieder herzustellen, programmieren wir die (Hilfs-) Klasse „starte_Klasse_1“, sodass sich die Klasse „Klasse_1“ wieder jederzeit
- und nicht nur beim Programmstart -
aufrufen und ausführen lässt: (Zum Vergrößern bitte
auf das Bild klicken!) Das Komplexe am Programm „micro_python-hallo_2-36.py“
ist eigentlich nur die Funktion „Funktion_1()“, wenn diese den Variableninhalt der Variablen „lokale_SendeVar“ ganz nach außen in die Funktion „anzeigen_Klasse_1()“ transferieren und an
die Variable „SendeVar“ in der Klasse „starte_Klasse_1“ übergeben soll (siehe
obenstehendes Bild). Aber da das Transferieren von
Variableninhalten nach außen bis ins Hauptprogramm
hinein eher die Ausnahme ist und bleibt, bleiben die Funktionen und ihre (Funktions-) Variableninhalte innerhalb der Klasse „Klasse_1“, sodass der Quellkode auch und gerade bei mehreren
Funktionen innerhalb einer
Klasse übersichtlich bleibt (siehe Programm
„oled_demo-01-29.py“). Im Programm
„micro_python-hallo_2-37.py“
wird es noch komplexer, aber nur deshalb, weil gezeigt wird, wie sich der Variableninhalt der lokalen Variablen „lokale_SendeVar“ der Funktion
„Funktion_1“ mittels der selbststartenden
Klasse „starte_Klassen_1u2“ bis ins Hauptprogramm
hinein mittels der Variablen „starte_Klassen_1u2.SendeVar“ weiterreichen lässt! Darüber hinaus lassen sich die
beiden Funktionen „anzeigen_Klasse_1()“ und „anzeigen_Klasse_2()“ zusammen mit ihren Klassen „Klasse_1“ und „Klasse_2“ jederzeit auch
vom Hauptprogramm aus aufrufen: (Zum Vergrößern bitte
auf das Bild klicken!) Übergeordnete Instanzen als Herrscher über alle Klassen
und Funktionen Bei der „Python“-Programmierung gibt es nicht
nur Funktionen und Klassen, sondern auch sogenannte Methoden, die nichts
anderes sind also Funktionen innerhalb einer Klasse. Dabei beschreibt eine
Methode das zielgerichtete Vorgehen zur Erlangung eines speziellen Zieles wie
z.B. bei einem Rezept oder einer Rezeptur. Wenn man sich bei einem Kochrezept die
entsprechenden Ressourcen (= Ausgangsmaterialien nebst Zutaten) besorgt und
sich streng an die Rezeptur, d.h. die Anleitung hält, wie man welche
Ressourcen zu einem bestimmten Zeitpunkt zusammen führt, d.h. miteinander
durch Rühren vermischt, dann kann beim Backen, Braten oder Kochen nichts
schief gehen, erreicht man mit ziemlicher Sicherheit sein Ziel in Form des
leckeren Kuchens oder Bratens. Wie wir inzwischen gelernt haben, lassen sich
Funktionen und Klassen sowie in Funktionen eingebettete Klassen
unterschiedlich handhaben, je nachdem, was bezweckt werden soll. Eine in eine Funktion eingebettete Klasse
bietet den Vorteil, dass sich die Klasse mehrfach wiederholt aufrufen und
starten lässt, indem man einfach die übergeordnete Funktion startet.
Wenn man dabei außerdem erreichen will, dass sich die Klasse auch mittels „Autostart“-Funktion beim Programmaufruf automatisch
startet, dann muss man zusätzlich noch eine entsprechende „Autostart“-Klasse programmieren, die beim Programmstart
dafür sorgt, dass die gewünschte Funktion nebst integrierter Klasse
aufgerufen, d.h. gestartet wird (siehe Klasse
„starte_Klassen_1u2“ im Programm „micro_python-hallo_2-37.py“).
In der Bundesrepublik Deutschland haben wir es
mit der Staatsform einer Demokratie zu tun, der das Grundgesetz (GG) als
Verfassung zugrunde liegt. Diesbezüglich gibt es in Deutschland das
sogenannte Gewaltmonopol, demzufolge Gewalt nur vom Staat selbst ausgehen
darf und niemanden sonst. Dabei stützt sich das Gewaltmonopol auf die
Gewaltenteilung von Legislative (= Parlament, Gesetzgebung), Exekutive (=
Ministerien zur Ausübung und Durchführung von Gesetzen und Verordnungen)
sowie Judikative (= Rechtsprechung durch Gerichte). Bezüglich der Rechtsprechung und der Gerichte
haben wir es in Deutschland auf der untersten Ebene mit dem sogenannten
Schiedsgericht zu, das je nach Bundesland meistens in die Zuständigkeit des
Ortsvorstehers z.B. eines Stadtteils oder eines Bezirksamtes fällt. Dabei
dient das Schiedsgericht dazu, kleinere Streitigkeit wie z.B. zwischen
Nachbarn zu schlichten. Wenn es in einem Stadtteil keinen Ortsvorsteher nebst
Schiedsgericht gibt, dann muss sich der Bürger im Falle Streitigkeiten an das
vor Ort in der Stadt oder Kreisstadt ansässige Amtsgericht wenden und Klage
einreichen. Wenn die Klage vom Amtsgericht abgelehnt oder durch Urteil
abgewiesen wird, dann kann man die nächst höhere Instanz anrufen und zwar in
Form des Landgerichtes. Falls die Klage auch vorm Landgericht scheitert, kann
man bei maßgeblichen Streitfällen oder Straftaten wiederum in Berufung gehen,
d.h. die nächst höhere Instanz anrufen und vor’s Oberlandesgericht ziehen. Ähnlich verhält es sich bei den
Staatsanwaltschaften, die für die Anklageerhebung zwecks Einhaltung von
Bestimmungen, Verordnungen und Gesetzen zuständig sind und die der Exekutive
zuzurechnen sind. Demzufolge ist die nächst höhere Instanz über der
Staatsanwaltschaft die Oberstaatsanwaltschaft. Und die wiederum nächst höhere
Instanz der Oberstaatsanwaltschaft ist die Bundesstaatsanwaltschaft mit der
noch darüber befindlichen, d.h. vorgesetzen Dienststelle und Dienstaufsicht
des Bundesgeneralanwaltes. Demzufolge kann der Generalbundesanwalt als
oberste Dienstbehörde der Staatsanwaltschaften die Ermittlungen im Falle
schwerer, verfassungsschutzrechtlicher Straftaten (= Terrorismus, terroristische
Vereinigung) der ansonsten zuständigen Oberstaatsanwaltschaft entziehen und
selbst ermitteln. - Bei höheren Programmiersprachen (kein
Assembler) geht es nicht wie bei der Landwirtschaft mit Kraut und Rüben
durcheinander, sondern mehr oder weniger geordnet zu. Während es bei der „BASIC“-Programmiersprache
mittels „gosub“-Sprungbefehlen noch kreuz und quer ging und man chaotischen
„Spaghetti“-Kode programmieren konnte, geht es bei den höheren, meist Objekt
orientierten Programmiersprachen (OOP)
wie z.B. Java, C/C++, C# von Microsoft, Python schon deutlich „gesitteter“
zu, gibt es z.B. keine direkten Sprungbefehle mehr! Auch in der „Python“-Programmierung gibt es keine
direkten Sprungbefehle, programmiert man seinen Programmkode anfangs
hauptsächlich im Hauptprogramm, das in anderen
Programmiersprachen „main“ heißt. Wenn dann der Programmkode umfangreicher wird
und Programmteile in einem bestimmten Zusammenhang stehen, etwas gemeinsam
miteinander zu tun haben oder z.B. eine bestimmte Funktionalität
beschreiben/programmieren, dann fasst man diesen zusammenhängen Programmkode
in einer Funktion zusammen. Wenn sich dann im Laufe der Zeit mehrere
Funktionen ansammeln, die alle
im Zusammenhang mit dem Erledigen einer Aufgabe zu tun haben, dann kommt man
auf die Idee, diese in einer Klasse zusammenzufassen.
Getreu dem Motto „Was ich alles in einer Klasse zusammengefasst habe, muss
ich nicht mehr im Kopf haben, funktioniert, kann ich ad acta legen.“ Dass man
aber mehrere Funktionen in einer Klasse zusammenfassen kann, ist nur die
halbe Wahrheit. Zur vollen Wahrheit gehört nämlich, dass man in einer Klasse auch sehr komfortabel Programmkode programmieren kann mit dem sich Funktionen aufrufen und Variableninhalte bequem austauschen
lassen, ohne dass man dazu das Hauptprogramm
bemühen muss. Wenn man dann aber früher oder später eine Klasse mehrfach, d.h. öfters aufrufen,
starten und ausführen möchte, so wie das z.B. bei der „Autostart“-Funktion
geschieht, gerät man schnell an seine Grenzen, könnte man letztlich auch
daran verzweifeln und scheitern. Es sei denn, wenn man eine innere Klasse(!) in eine äußere Funktion(!) integriert, da sich Funktionen mit der darin enthaltenen Klasse oder
Klassen jederzeit aufrufen und ausführen lassen (siehe Programm „micro_python-hallo_2-37.py“)!
Im Zusammenhang mit dem Programm
„micro_python-hallo_2-37.py“ stellt sich dann auch früher oder später die
Frage, ob sich komplexe Funktionen und/oder Klassen zu etwas Höherem berufen lassen, die
sozusagen über allen Funktionen und/oder Klassen stehen und eine höhere, weil
mächtigere Instanz bilden. Eine Instanz als alleiniger Herrscher und Beherrscher
aller, d.h. mehrerer Klassen und Funktionen. Beim Programm
„micro_python-hallo_2-38.py“
gibt es gleich zwei Instanzen und zwar 1.
die Instanz „InstanzVar_Funktion_anzeigen_Klasse_2“ in Form der Funktion „anzeigen_Klasse_2()“ mit dem (Rückgabe-)
Statement „return(Klasse_2.EmpfangsVar)“ an die vorgenannte Instanzvariable und 2.
die Instanz „InstanzVar_Klasse_starte_Klassen_1u2“ in Form der (Klassen-) Variablen „starte_Klassen_1u2.EmpfangsVar“
an die Instanzvariable. Wie man unschwer sieht, handelt es sich bei
beiden Instanzen in Wirklichkeit um Instanzvariablen nebst deren Inhalten: (Zum Vergrößern bitte
auf das Bild klicken!) Wie man im abgespeckten Programm „micro_python-hallo_2-39.py“
sieht, (Zum Vergrößern bitte
auf das Bild klicken!) kann beim Arbeiten mit den Instanzen „Instanz_anzeigen_Klasse_2“ und „Instanz_starte_Klassen_1u2“ auf die Klasse „starte_Klassen_1u2“ ganz verzichten,
weil die beiden Instanzen selbst der Funktion „anzeigen_Klasse_2()“ entsprechen! Im Moment sieht es also so aus, als ob das
Arbeiten mit der Instanz
„anzeigen_Klasse_2“ außer der verkürzten
Schreibweise keine besonderen Vorteile ergibt. Diesbezüglich stellt sich die Frage, ob es
besondere Vorteile bringt, wenn man eine Klasse
zur Instanz erklärt. – Um das zu klären, wenden wir uns wieder dem
Programm „micro_python-hallo_2-35.py“
zu, das wir auf das Programm „micro_python-hallo_2-40.py“
kopieren und wie folgt erweitern: (Zum Vergrößern bitte
auf das Bild klicken!) Besonders interessant an der Instanz „Instanz_Klasse_1“ ist nun, dass sich mittels dieser sowohl · die Funktion „Funktion_1()“ als auch · die Klassenvariable „SendeVar“ direkt ansprechen, aufrufen und benutzen lassen. Und
zwar ohne den Umweg über das · Statement „rueckgabeWert = Klasse_1.Funktion_1()“ als auch · Statement „print(“Inhalt der Klassenvariablen ’SendeVar’:
“, Klasse_1.SendeVar)“
Werfen wir abschließend noch einen Blick auf
die Bildschirmausgabe des Programms „micro_python-hallo_2-40.py“:
(Zum Vergrößern bitte
auf das Bild klicken!) Bezüglich der Instanz „Instanz_Klasse_1“ muss noch
festgestellt werden, dass sich damit die Klasse
„Klasse_1“ selbst wider
Erwarten nicht noch ein weiteres Mal starten und ausführen lässt! - Weiter zum „Micropython“-Programmieren, Teil 3“ |
||||||||||
|
[ Home ] [ Seitenanfang ] |
|