|
|
Die erste Aufgabe |
Zur Kursübersicht |
|---|
|
Eine kleine Shell im Textmodus Mit mehreren ToDo - Listen arbeiten |
eine erste class selber formulieren
Folgende Anmerkungen sind für dieses kleine Programm zu machen: Es ist möglich, mit Python sowohl in der klassischen prozeduralen Form zu programmieren, als auch in objektorientierter Form. Wir wollen hier einfach mal mit der objektorientierten Form einsteigen. Wenn man sich Listing 1 anschaut, fallen sofort einige besondere Schlüsselwörter auf, die nachfolgend beschrieben werden: # class def __init__ Beispiel = classname(Parameterliste) In diesem Beispielfall wird die Variable Beispiel
eine Instanz der Klasse "classname". self class test: t = test() >>> alles ok. Was ist passiert? Die Instanz t von der Klasse test hat natürlich die Eigenschaften der Klasse mitgeerbt. Dazu gehört hier die Variable self.text, die für die Instanz t nun t.text heißt. Der Name self ist also durch den eigenen Namen der Instanz ersetzt worden. Ebenso verfügt t über die funktion2. Wird sie für t mit t.funktion2() aufgerufen, dann wird sie so ausgeführt, dass alle "selfs", die in der Funktion vorkommen, als t gelesen werden. Daher kommt t.text auch in seiner aktuellen Belegung als Ausgabe. liste append( ) liste = append(neuElement) Wenn wir den kleinen
Quelltext herauskopiert haben, speichern wir ihn in der
Datei "todo.py" Also geben wir aus dem laufenden Python - Interpreter ein: >>> from todo import * womit wir unserem Python alle diese Funktionen bekannt gemacht haben. Nun leiten wir uns einen eigenen Notizblock ab, den wir "n" (für Schreibfaule) nennen wollen. >>> n = notiz() Das sollte Python ohne
Meckern schlucken. Zwischen den Klammern der Funktion steht
übrigens nichts. Unser konkreter Notizblock heißt
jetzt n, der
nach dem Bauplan der Klasse notiz gebaut ist. In der speziellen Instanz n hat also die
Variable self den Wert n. >>> n.zeige() []
>>> Diese Antwort verwundert nicht, denn der Notizblock ist noch leer. Man hätte dieses Ergebnis übrigens auch mit dem manuellen Befehl print n.liste erzeugen können. Aber in der objektorientierten Programmierung soll man mittels Funktionen auf die Daten der Klasse zugreifen, damit garantiert ist, dass auch nur gültige und definierte Veränderungen an unseren Daten möglich sind. Aber für Zwecke der Fehlersuche beim Programmieren zum Beispiel ist so etwas ganz legitim. Nun schreiben wir mal was drauf, auf unseren Notizzettel. Dazu verwenden wir die vorbereitete Funktion hinzu( ), die einen Parameter erwartet, der hier ein String sein sollte. Dieser wird durch die Funktion an unsere Liste angefügt. >>> n.hinzu('Eintrag 1') Auch das wird kommentarlos
hingenommen. Es kommt auch keine Antwort, da wir die nicht
programmiert haben. Wir können diese
Antwort aber herbeiführen: >>> n.zeige()
['Eintrag 1']
Na bitte, der Zettel ist nicht mehr leer! Nun können wir immer so weiterprobieren und immer mehr hinzufügen. Wenn wir das Programm verlassen, ist alles wieder weg. Aber diese Arbeitsstufe war ja nur zum ersten Kennlernen gedacht. Es fehlt u.a. noch die wichtige Funktionen des Abspeicherns der gesamten Notizliste. Dazu nehmen wir uns Listing 2 her. Das Abspeichern erreichen wir, in dem wir unsere Notizliste in eine Datei auslagern. Beim Aufruf des Programms wird dann nachgesehen, ob es diese Datei schon gibt. Ist dies der Fall, dann wird sie in den Notizzettel hineingeladen. Wenn nicht, wird mit einem leeren Zettel angefangen, was sonst :-). Beim Beenden des Programms wird der Notizzettel abgespeichert. Soweit erstmal zur Idee. Wie arbeitet man nun mit
Dateien (öffnen, schreiben, lesen, schließen)? f = open('MyNotes', "r") hier zum lesen (read) der
Daten oder
f = open('MyNotes', "w")
dagegen zum schreiben (write) der Daten. Mit der Variablen f wird dann jeweils die Datei angesprochen, z.B. durch f.write('weiterer Text') Nach beendeter Benutzung der Datei wird diese wieder geschlossen, wie in vielen anderen Programmiersprachen auch. f.close() In unserem Beispiel wurde in die Datei jedoch nicht direkt mit write hineingeschrieben, sondern wir haben das Modul pickle benutzt. Mit der Zeile import pickle haben wir es hinzugeladen. Pickle erlaubt es, Objekte wie Strings, Listen usw. bis hin zu kompletten Klassen "einzulegen", das heißt durch organisierende Steuerzeichen ergänzt, in einen Datenstrom zu verwandeln, den wir dann in unsere Datei hineinschieben. pickle.dump(self.liste, f) So ist es programmiert, zum Abspeichern der Notizliste vor Beendigung des Programms. Umgekehrt werden die Daten beim Laden aus der Datei vor der Verwendung "entpickelt" :-) self.liste = pickle.load(f) Ansonsten ist alles geblieben wie beim vorigen Beispiel. Ach halt, etwas habe ich noch vergessen. Das Abspeichern beim Beenden des Programms erfolgt noch nicht automatisch (das kommt aber noch!). Wir müssen es mit der Hand ausführen. Durch den Aufruf: n.rette() geschieht dies auch, sofern wir vorher unseren Notizzettel mit n = notiz( ) erzeugt hatten. Die beiden an dieser Stelle noch nicht besprochenen Befehle try und except dienen hier dazu, einen Fehler abzufangen, der speziell beim erstmaligen Start dieses Programms auftritt, weil es ja da das File "MyNotes" noch nicht gibt. Das ändert sich, sobald die Funktion n.rette erstmalig aufgerufen wurde. Die Fehlerbehandlung ergab sich aus einen Hinweis von Juergen Scheuer, dem auffiel, dass das Modul früherer Fassung beim Erststart einen Fehler erzeugt.Es ist ohnehin sinnvoll solche Fehler abzufangen, weil es durch Verschieben des Quelltextes ohne das File schnell mal versehentlich fehlen könnte. Wenn unser Programm dann weiter ausgebaut wird, wird sich noch eine andere Lösungsmöglichkeit mit dem Modul os zeigen. Noch am Rande ein anderes kleines Problem, besonders wenn man das Programm gleichzeitig unter Linux und Windows nutzt. In den Notizzeilen können natürlicherweise auch Umlaute (ÄÖÜäöü) sowie ß vorkommen. Soll eine mit Windows erzeugte Notiz unter Linux gelesen werden oder umgekehrt. gibt es da Darstellungsprobleme. Die einfachste Abhilfe wäre, diese Zeichen zu vermeiden. Etwas aufwendiger wäre es, eine spezielle Codierung für diese Zeichen zu erfinden, die das Programm dann selbst wieder auflöst. Da die neueren Versionenvon Python nun mit Unicode arbeiten, könnte das Problem damit beseitigt werden. Das schauen wir uns aber später an. :-) Steuern unseres kleinen Moduls mit einer einfachen Bedienoberfläche Bisher war unser kleines Beispielprogramm eigentlich nur eine Funktionssammlung, die immer mit der Hand zur Ausführung gebracht wurden. Nun wollen wir auf diese Sammlung von verschiedenen Funktionen noch eine kleine Bedienoberfläche draufsetzen. Diese läuft als Schleife, in der Kommandoeingaben abgefragt und ausgewertet werden. Die verfügbaren Kommandos können mit der help - Funktion sichtbar gemacht werden. Wie sieht solche kleine shell nun aus? Hier mal ein Beispiel im Kommandofenster von Windows. Hier wurde als Eingabeaufforderung das Zeichen % verwendet. Nun wird einer der erwarteten Zeichen + Enter (die Zeichen sind hier durch Einklammerung hervorgehoben) die dazu passende Funktion auslösen. Mit "q" + Enter wird das Programm verlassen. Jetzt läuft natürlich auch das Hinzuladen sowie Abspeichern der Daten für den Nutzer unbemerkt (außer dass dem Nutzer auffällt,dass das Programm nun nichts mehr vergisst). Der Programmquelltext ist in in diesem Listing nachzulesen. Welche Funktionen sind nun verfügbar? Neben der Funktion h = help, die die Zeile mit den möglichen Befehlen erneut auswirft, gibt es die Kommandos: l = list: Ausgabe aller
Notizzettelzeilen untereinander Welches Programmstück wird nun wann und wofür abgearbeitet? Die folgenden Erläuterungen sind jetzt etwas gröber als zu Anfang, da wir ja inzwischen schon immer mehr über Pythonprogramme wissen. Die bereits bekannten Funktionen wurden etwas ausgebaut. Das bitte ich, selbst zu vergleichen und auszuprobieren. Aber was ist jetzt echt neu? Da fällt ein ganz neuartiger Programmteil auf: # ab hier Hauptprogramm
if __name__ ==
'__main__':
try: n = notiz() n.version() n.list() n.help() n.shell() except EOFError: pass print 'bye' Wenn in einem Modul neben den Klassen- und Funktionsdefinitionen noch Befehlszeilen stehen,werden die vom Interpreter sofort ausgeführt. Die Variable __name__hat nur dann den Namen __main__,wenn das Modulals Hauptmodul gestartet wird. Dient es nur als Funktionssammlung eines anderen aufrufenden Moduls, dann hat es den Namen nach seinem Dateinamen (also z.B. todo) Die Befehle in diesem Programmblock sollen nur arbeiten, wenn todo das Hauptprogramm ist. Wollen wir die Funktionen für etwas anderes nutzen (dieser Fall kommt noch, wenn wir die grafische Oberfläche drauflegen), würden diese Befehle nur stören. Nun wird hier automatisch allerlei gemacht. So erzeugt das Programm für uns die Instanz n von notiz.Weiterhin wird eine wichtige Funktionaufgerufen,die n.shell( ) heißt. Hier wird auf unsere Eingaben gewartet und die zu den Kommandos passenden Funktionenaufgerufen. Die shell läuft in einer while - Schleife mit der Bedingung 1 (dauerwahr), bis wir das durch den Kommando quit mit dem Befehl break (Herausspringen aus der Schleife) beenden. def shell(self):
Folgende Funktionen zur Verwaltung der Liste
könnten noch sinnvoll dazugenommen werden, wie Dies sind nur Beispiele, der eigenen
Kreativität sind keine Grenzen gesetzt. :-) Verwalten der ToDo's in mehreren Listen Als nächsten Schritt
wollen wir unser ToDo-Programm etwas ausbauen, da es uns
nicht ausreicht, alle wichtigen Aktivitäten in einer
einzigen Liste zu verwalten. Viel besser wäre es,
wenn wir mit mehreren Listen arbeiten könnten,
zwischen denen man "umschalten" kann. Gearbeitet wird mit
der jeweils "aktuellen Liste".
|