Python Kurs
Python Kurs
Martin Schimmels
W ICHTIG
Druck dieses Buch nicht aus!!!
Im Online-Dokument kann man suchen, springen, es wird (hoffentlich)
ständig verändert und verbessert. Und es benötigt nicht eine wichtige
natürliche Ressource: Papier.
Dieses Skript steht unter der Creative Commons Lizenz BY-NC-SA, auf Deutsch, Creative Commons
”
Namensnennung-Keine kommerzielle Nutzung-Weitergabe unter gleichen Bedingungen.“
Diese Lizenz erlaubt es, das Skript zu benutzen, zu ergänzen, zu verändern, Inhalte umzustellen. Diese
Lizenz erlaubt es nicht, das Skript für kommerzielle Zwecke zu nutzen. Der Link zu dieser Lizenz ist
<[Link]
Nachfolgend steht die Zusammenfassung der wichtigsten Teile der Lizenz:
• Das Skript darf vervielfältigt, weitergegeben und öffentlich zugänglich gemacht werden.
• Das Skript darf verändert werden.
• Ich als Autor muss in Kopien genannt werden.
• Das Skript darf nicht kommerziell verwendet werden.
• Veränderte oder bearbeitete Versionen dieses Skriptes müssen unter der selben Lizenz stehen.
Das heißt auch, dass solche Versionen genau wie dieses Skript einen Link zur Lizenz enthalten
müssen.
3
Inhaltsverzeichnis
I. Grundlagen 25
1. Was ist Python? 27
1.1. Der Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.2. Was für eine Sprache? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.3. Warum Python und nicht eine andere Sprache? . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.4. Ausführung von Python-Programmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2. Programmieren 33
2.1. Was heißt Programmieren“? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
”
2.1.1. Warum soll man überhaupt programmieren lernen? . . . . . . . . . . . . . . . . . . 34
2.1.2. Sprache lernen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.1.3. Übersetzung ... in welche Sprache denn? . . . . . . . . . . . . . . . . . . . . . . . . 35
2.2. Was ist also ein Programm? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3. Geschichte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4. Was braucht man, um mit Python zu arbeiten? . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.5. Hilfsprogramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.6. Voraussetzungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.6.1. Das Dateisystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.6.2. Regeln für Dateinamen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.6.3. Datei-Operationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.7. Was heißt Programmieren“? Fortsetzung! . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
”
2.7.1. Strukturierte Programmierung: Ein Überblick . . . . . . . . . . . . . . . . . . . . . 40
2.8. Objektorientierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.9. Programmierstil und Konventionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.10. Reservierte Wörter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.11. Fehler (zum ersten) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.12. ... und das fehlt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.13. Fehler finden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.14. Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
II. IDE 49
3. Die Entwicklungsumgebung IDLE: Zahlen und Variable 51
3.1. . . . und bevor es losgeht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2. Rechnen in der Entwicklungsumgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.2.1. Aufgaben zu Zahlen und elementaren Berechnungen . . . . . . . . . . . . . . . . . 58
3.3. Ein Speicherplatz mit einem Namen: Variable . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.3.1. Variable in Mathematik und in der Programmierung . . . . . . . . . . . . . . . . . 58
3.3.2. Variablennamen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.3.3. Wertzuweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.3.4. Aufgaben zu Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.3.5. Zuweisungsmuster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.4. Bruchrechnen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.5. Rechnen und vergleichen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.5.1. Zahlen, Zahlen, Zahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.5.2. Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
[Link]. Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
[Link]. Verschiebeoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.5.3. Komplexe Zahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.5.4. Andere Zahlsysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.5.5. Zufall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
[Link]. Zufällige ganze Zahlen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
[Link]. Zufällig ausgewählte Buchstaben aus einer Textzeile . . . . . . . . . . . . 73
5
Inhaltsverzeichnis Inhaltsverzeichnis
3.6. Shortcut-Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4. Richtig programmieren 75
4.1. Entwicklungsumgebungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.1. Die Entwicklungsumgebung Eric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.2. IDE unter Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.3. So sieht’s aus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.1.4. Der Programm-Rahmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.2. Das absolute Muss: Hallo Ihr alle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.3. Die ersten einfachen Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6
Inhaltsverzeichnis Inhaltsverzeichnis
7
Inhaltsverzeichnis Inhaltsverzeichnis
8
Inhaltsverzeichnis Inhaltsverzeichnis
9
Inhaltsverzeichnis Inhaltsverzeichnis
10
Inhaltsverzeichnis Inhaltsverzeichnis
[Link] 411
Glossar 416
E. Index 459
11
Abbildungsverzeichnis
0.1. 6 einfache quadratische Spiralen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
0.2. 6 verdrehte quadratische Spiralen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
0.3. 3 sechseckige Spiralen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4. Richtig programmieren
4.1. Die IDE Eric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.2. Die IDE PyScripter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
5. Texte
5.1. Texte in der IDE Idle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.2. Multiplikation von Texten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6. Strukturierte Daten
6.1. Struktogramm binäre Suche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
10. Klassen
10.1. Klassendiagramm Mensch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
10.2. Klassendiagramm Schueler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
13
Abbildungsverzeichnis Abbildungsverzeichnis
20. CGI-Programme
20.1. Eingabe-Formular in HTML(Namen) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
20.2. Eingabe-Formular für eine Rechnung in HTML . . . . . . . . . . . . . . . . . . . . . . . . . 334
20.3. Ausgabe einer Rechnung in HTML (aber wirklich nicht schön) . . . . . . . . . . . . . . . . 338
20.4. Ausgabe einer Rechnung in HTML (so kann man das akzeptieren) . . . . . . . . . . . . . 341
14
Tabellenverzeichnis
2. Programmieren
2.1. Betriebssystem-Befehle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5. Texte
5.1. Steuerzeichen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5.2. Zeichenkette als Feld betrachtet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
5.3. Format-Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.4. Format-Option-Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.5. Parameter für die format-Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.6. Reguläre Ausdrücke: Zeichen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.7. Reguläre Ausdrücke: Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
6. Strukturierte Daten
6.1. Liste mit Hausnummern und Einträgen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.2. Überblick Strukturierte Daten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7. Programmstrukturen
7.1. UND-Verknüpfung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7.2. ODER-Verknüpfung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7.3. NICHT-Verknüpfung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
7.4. Übung zu Wahrheitswerten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
7.5. Pseudocode und Python-Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
7.6. Notendurchschnitt: Pseudocode und Python-Code . . . . . . . . . . . . . . . . . . . . . . . 164
7.7. Pseudocode und Python-Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
7.8. Schlüsselwort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
7.9. Verschlüsselung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
10. Klassen
10.1. Sichtbarkeit und Kapselung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
12. Fehler. . .
12.1. Fehler-Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
15
Vorwort
Typographische Konventionen
Bei manchen Kapiteln stehen solche Bilder voran. Sie sind mit Python und der Bibliothek turtle“ ge-
”
malt. Wer sich über die Schildkröte informieren möchte, sollte einfach im Internet suchen. Vorschläge
für Suchbegriffe: turtle, logo, Seymour Papert
Jetzt fängt das Buch aber richtig an. Zuerst muss hier aber einmal geklärt werden, was die verschie-
denen Schriftarten in diesem Buch bedeuten:
• Schreibmaschinenschrift wird für Code(-Fragmente) benutzt. Ebenso werden Variablennamen
in Schreibmaschinenschrift gesetzt.
• Befehlsnamen werden fett gesetzt.
• Dateinamen werden in Schreibmaschinenschrift gesetzt.
• Ein- und Ausgaben in IDLE werden wie folgt gesetzt. Eingaben sind an den >>> zu erkennen.
>>> print(’Hallo’)
Hallo
T IPP
Randnotizen stehen im Online-Dokument in einem blauen Kasten.
Randnotizen stehen im gedruckten Text in einem Rahmen mit einem ein-
gekreisten großen i“ am Rand.
”
W ICHTIG
Wenn etwas besonders wichtig ist, steht das im Online-Dokument in einem
orange-roten Kasten.
Wenn etwas besonders wichtig ist, steht im gedruckten Text am Rand ein
Ausrufezeichen in einem Kreis.
A NMERKUNG
Eine Anmerkung steht im Online-Dokument in einem grünen Kasten.
Auf eine Anmerkung wird im gedruckten Text durch den ausgestreckten
Zeigefinger hingewiesen.
Anmerkungen werden insbesondere auch benutzt, um auf Änderungen in
Python 3.x im Verhältnis zu Python 2.x hinzuweisen.
17
VORWORT
A CHTUNG
Das Achtung-Zeichen weist auf eine Situation hin, bei der leicht ein Fehler
gemacht werden kann. Wenn etwas besonders wichtig ist, steht im ge-
druckten Text am Rand ein Ausrufezeichen in einer Raute.
Das wird im Online-Dokument durch einen violetten Kasten hervorgeho-
ben.
Freiheit
Dieser gesamte Text ist frei im Sinne der Freien Software“. Er steht unter der CC BY-NC-SA“, die unter
” ”
dem Link <[Link] nachzulesen ist.
Das bedeutet, dass dieser Text beliebig kopiert und verbreitet werden darf. Er darf auch modifiziert
werden.
Das Urheberrecht dieses Textes bleibt bei mir. Die wichtigste Bestimmung ist, dass dieser Text immer
unter der CC BY-NC-SA bleibt, auch wenn er von Dir verändert wird, und dass die CC BY-NC-SA
immer Teil dieses Textes sein muss.
Du darfst beliebig viele Kopien dieses Textes auf beliebigen Medien machen. Auf jeder Kopie muss
aber ein urheberrechtlicher Vermerk aufgeführt sein und die CC BY-NC-SA muss Teil der Kopie sein.
Den eigentlichen Text darfst Du nach Deinen Vorstellungen bearbeiten, Teile hinzufügen, Verbesse-
rungen anbringen, Teile weglassen, sofern Du einige Regeln einhältst
1. Der veränderte Text muß deutlich sichtbare Vermerke enthalten, die die Veränderung, den Autor
der Veränderung und das Datum der Veränderung angeben.
2. Der veränderte Text verbleibt unter der CC BY-NC-SA und enthält die CC BY-NC-SA.
3. Der Text darf nicht in ein proprietäres Format umgewandelt werden.
4. Eine Kopie des veränderten Textes wird mir zugesandt.
Dieser Text ist in DocBook-XML geschrieben. Dabei habe ich mich an die Spezifikationen gehalten,
wie sie in dem Buch von [DocBook-XML] beschrieben wird. Sollte jemand diesen Text im Docbook-
XML-Format weiterverarbeiten, soll er sich per Mail an mich wenden.
Da ich selber es absolut unerträglich finde, wenn Fachbücher der Informatik in schlechtem Deutsch
geschrieben sind,3 4 bitte ich auch alle Leser, dass sie mir eventuelle sprachliche Fehler mitteilen, gerade
auch wenn es nur Leichtsinnsfehler oder kleinere Ungenauigkeiten sind. 5
3 Es ist leider betrüblich zu sehen, wie viele Autoren geraden von Fachbüchern im Bereich der Datenverarbeitung ihre Mutter-
sprache nicht mehr beherrschen. Zeichensetzung und Rechtschreibung folgen da oft Regeln, die niemand zuvor gehört hat —
und der Autor kurz danach wieder vergessen hat. Manchmal fragt man sich da, ob der Autor schon jemals ein Programm in
welcher Programmiersprache auch immer geschrieben hat, wenn man weiß, mit welcher Genauigkeit man dabei sprachliche
Regeln einzuhalten hat.
Besonders peinlich sollte das für das Lektorat eines Verlages sein, aber auch da hat man manchmal das Gefühl, dass dort
Analphabeten eingestellt worden sind. Die typische Reaktion, wenn man einen solchen Lektor auf einen Fehler hinweist, ist
dann ein Haben Sie etwa noch nie einen Fehler gemacht?“
”
4 Von Frau A.F. habe ich gelernt, dass Schüler inzwischen in Bezug auf die Zeichensetzung nur noch die 5-cm-Regel kennen:
Setze alle 5 Zentimeter ein Komma.
5 Ich bitte wirklich ausdrücklich darum, mir Dinge NICHT durchgehen zu lassen, die heutzutage an Schulen viel zu vielen
18
VORWORT
Gleichberechtigung
In diesem ganzen Text wird immer für einen generischen Begriff nur das in der deutschen Sprache
übliche grammatikalische Geschlecht benutzt. Eine Fachkraft oder sogar eine Koryphäe auf dem Gebiet
der Python-Programmierung kann also durchaus auch mal ein Mann sein und ein Python-Programmierer
auch eine Frau. Vor allem bei der Bezeichnung von mehreren Personen, vulgo Plural genannt, vermei-
de ich so unschöne Formulierungen wie Python-Programmiererinnen und Python-Programmierer“.
”
Sollte jemand daran Anstoß nehmen, so steht jedem Leser es frei, den Quelltext mit einem (zum Bei-
spiel in Python selbstgeschriebenen) Programm und mit den in diesem Text erworbenen Kenntnissen
und einigem Zusatzwissen in XML (hierzu bietet sich das Buch von Drake [Python and XML] an) so
abzuändern, dass solche generischen Begriffe in eine nach seinen Vorstellungen politisch korrekte Form
umwandelt werden. 6
Dieses Buch kann man natürlich überall lesen, am Schreibtisch, auf dem Balkon, vor dem Fernsehgerät,7
am Strand . . . . Bei vielen Kapiteln ist es aber ganz sinnvoll, dass man dieses Buch am Arbeitsplatz vor
sich nimmt, Computer eingeschaltet und alles so vorbereitet, dass man sofort den einen oder anderen
Python-Befehl eingeben kann oder eine kleine Übung machen kann, ein Programm schreibt, weil durch
das Lesen die Idee zu einem Programm kommt . . .
Eine Begründung
Ich höre und vergesse.
Ich sehe und erinnere mich.
Ich tue und ich verstehe.
(Konfuzius 8 )
Aber warum sollen wir eigentlich programmieren lernen? Computer sind inzwischen zu einem Werk-
zeug geworden, von dem man wie etwa von dem Werkzeug Staubsauger“ nicht mehr wissen muss,
”
wie es funktioniert, um es zu bedienen. So jedenfalls wird das uns in der Werbung immer wieder gesagt.
Ist das wirklich so?
Nun, zu welcher Gruppe von Menschen willst Du gehören? Der Gruppe derjenigen, die bedienen
können, ohne zu verstehen? Oder zu der Gruppe derjenigen, die verstehen und die Maschine beherr-
schen? Man muss sich klar machen: Computer machen genau das, was man ihnen sagt“, und das
”
machen sie richtig gut, ohne Widerspruch, skrupellos. Vielleicht will ich doch lieber zu der Gruppe
gehören, die dem Computer sagen kann, was er tun soll.
Einfache Aufgaben sollten einfach gelöst werden. Einfach ist schön, einfach ist elegant. Auf dem Ge-
biet der Programmierung heißt das: das Zusammenklicken eines Programms ist vor allem für Anfänger
abzulehnen, weil dadurch das Programm, das man schreiben will, undurchschaubar wird. Durch diese
Methode der Software-Produktion werden Bibliotheken, Module, Klassen eingebunden, die die Logik
6 Wenn es sein muss, sogar mit dem grossen Binnen-I. horribile dictu.
7 Ja, es soll wirklich Fernsehsendungen geben, bei denen man nichts versäumt, wenn man wegschaut — und manchmal ist es
trotzdem besser, man bleibt vor der Glotze hängen.
8 sinngemäß unter: <[Link]
19
VORWORT
des Problems verschleiern, die Platz kosten, die das Programm langsam machen, die ein Programm
unleserlich machen. Die Folge davon ist: eine komplizierte Lösung erfordert komplexe Resourcen.
Andere Sprachen
Deswegen soll an einem alltäglichen Beispiel demonstriert werden, wie das alltägliche Problem in ver-
schiedenen Sprachen gelöst wird. Vor allem wird das oben genannte Vorgehen realisiert, also auf allen
Schnickschnack verzichtet, der heutzutage zu einem richtigen“ Programm gehört: eine grafische Ober-
”
fläche fehlt, Eingabemasken fehlen. Das Programm benutzt nur die Shell (die bei anderen Betriebssys-
temen Eingabeaufforderung“ heißt.)
”
Ein Programm soll einen Text von der Standard-Eingabe entgegennehmen. Der Begriff Standard-
”
Eingabe“ bedeutet, dass in der Umgebung, in der das Programm ausgeführt wird, über die Tastatur
etwas eingegeben wird. Dies bedeutet insbesondere weiter, dass nicht etwa eine grafische Oberfläche
geschaffen wird, in der sich vielleicht ein Fenster öffnet, in das man etwas eingeben kann. Damit man
auch sieht, was man eingegeben hat, wird die Eingabe danach auch noch ausgedruckt. Das macht das
Programm natürlich viel länger !!! Dazu folgen hier 3 Lösungen in 3 Programmiersprachen:
$s = <> ;
print $s;
$s = <STDIN> ;
print $s;
Was fragt der typische Schüler, wenn er dieses Stück Programmcode sieht?
• Warum steht da ein Dollar-Zeichen?
• Was heißt STDIN“?
”
• Warum steht das STDIN“ in größer-kleiner-Zeichen?
”
• Muss da ein Strichpunkt stehen?
2. In Python geht das fast noch kürzer:
Das funktioniert, aber das ist nicht besonders schön, deswegen schreibt man in Python oft we-
sentlich mehr. In beiden Fällen erhält aber man auch wesentlich mehr Komfort, nämlich eine aus-
drückliche Aufforderung, etwas einzugeben:
s = input(’Text eingeben: ’)
print(s)
Was fragt der typische Schüler, wenn er dieses Stück Programmcode sieht?
• Was heißt input“?
”
• Warum steht der Text in Anführungszeichen?
3. In Java sieht das Programm-Fragment so aus:
import [Link].*;
public class stdLesen {
public static void main(String[] args)
throws IOException{
BufferedReader eingabe =
20
VORWORT
Was fragt der typische Schüler, wenn er dieses Stück Programmcode sieht?
• Was bedeutet [Link].*“?
”
• Was bedeutet importieren?
• Was bedeutet public“?
”
• Was heißt class“?
”
• Was bedeutet static void main“?
”
• Was bedeutet String[] args“?
”
• Was heißt throws“?
”
• Was ist eine IOException“?
”
• Was sollen die vielen geschweiften Klammern?
• usw.
Ich bin sicher, dass jeder Lehrer zustimmt, wenn ich sage, dass für fast jedes Wort und fast jedes
Zeichen hier eine Frage nach dem Sinn auftauchen wird.
4. Und zum Schluß kommt das entsprechende C++-Programm.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string t1;
cin >> t1;
cout << t1 << endl;
return 0;
}
Kein Kommentar! Aber falls jemand Lust verspürt: einfach mal ein paar Kommentare sammeln
von absoluten Programmieranfängern.
Entscheidungskriterien
Man kann die Entscheidung für eine Programmiersprache nach vielen Kriterien treffen. Ein Unter-
nehmen wird die Wirtschaftlichkeit einer Sprache weit oben ansiedeln. Eine interessante (wenn auch
schon etwas ältere) Gegenüberstellung findet man bei Steve Ferg unter <[Link]
org/wiki/Compiler>. Aber Wirtschaftlichkeit sollte nicht nur unter dem Kostenaspekt gesehen wer-
den. Auch in der Bildung ist Wirtschaftlichkeit ein Kriterium, nämlich wenn man der Frage nachgeht,
wieviele Fehlermöglichkeiten eine Sprache bei verschiedenen Konstrukten enthält. Hier ist eine knappe
Sprache wie Python deutlich im Vorteil. Auch hierzu gibt es in oben genanntem Artikel von Ferg einige
Beispiele.
Für den Unterricht, sei es in der Schule oder sei es an der Hochschule, stellen sich die Fragen nach der
Lernkurve (steil oder flach), nach der Modellhaftigkeit der Sprache und der Mächtigkeit der Sprache.
Die Mächtigkeit der Sprache ist allerdings in der Schule von untergeordneter Bedeutung. Jede Program-
miersprache ermöglicht es, alle Probleme, die etwa in einem 2- oder 4-stündigen Kurs auftreten, zu
lösen.
21
VORWORT
Entscheidung
Hier sollte sich jeder Lehrende kurz überlegen, wie er vorgehen würde, wenn er seinen Schülern er-
klären sollte, was die Befehle bedeuten. Würde er sagen: #include<iostream>, #include<string>, using
namespace std;, cin usw. ignorieren wir einfach mal, das kommt später? Oder würde er wirklich die
einzelnen Sprachelemente erklären? Wie lange bräuchte er wohl dazu? (Eine kleine Entscheidungs-
hilfe, aber leider nur für die Sprache Java: In einem der Standardbücher zu [Java] steht ein ähnliches
Programm-Fragment, das dieses Problem löst, auf Seite 612.) Wenn er die erste Methode wählt: wie-
viele Zuhörer würden Programmierung als etwas sehen, das in der Nähe von obskuren Voodoo-Kulten
anzusiedeln ist, aber für Normalsterbliche völlig unverständlich ist. Und wenn er die zweite Metho-
de wählt: wieviele Programmieranfänger würden diesen Erklärungen gerne folgen, sie verstehen und
sagen: mehr davon!
Man könnte das Beispiel vereinfachen und das Standard-Programm, das jedem Anfänger in fast je-
der Programmiersprache vorgeschlagen wird, seit Kernighan/Ritchie ihr Werk über die Sprache C“
”
geschrieben haben, das Programm, das nichts tut außer den Text Hallo, world!“ ausgeben, in verschie-
”
denen Programmiersprachen untersuchen (dann müssen natürlich C“ und C++“ auch dabei sein!).
” ”
Vor allem die Schüler sind es, die mit Recht eine Abkehr von den bisher benutzten Unter-
richtssprachen verlangen, weil die damit fabrizierten Produkte in der Regel keinen Wieder-
erkennungswert mehr besitzen im Vergleich zu den sonst vorherrschenden Programmen.
Es besteht allerdings die Gefahr - insbesondere beim Einsatz moderner Entwicklungsober-
flächen und Interface-Buildern“, wie sie z.B. bei Delphi üblicherweise eingesetzt werden -
”
dass nun schöne bunte Programme entstehen, die Vermittlung wichtiger Informatik-Konzepte
aber zu kurz kommt. 9
Man kann eine Programmiersprache erst dann, wenn man selbständig in ihr Programme
schreiben kann.
Weil learning by doing“ in der Programmierung nicht nur ein netter Spruch ist, sondern wirklich das
”
einzig erfolgversprechende Rezept, sollte jeder Lernende möglichst viele Übungsaufgaben machen. Ein
paar Aufgaben sind bereits am Ende mancher Kapitel aufgeführt. Im Sinne des oben Gesagten sollte
jeder sich ermutigt fühlen, Aufgaben hinzuzufügen.
9 aus: <[Link]
10 aus: <[Link]
22
VORWORT
Wer Programmieren lernt, der wird Probleme als solche erkennen lernen. Fortschritte dabei bedeuten,
dass man immer mehr Lösungsstrategien sich erarbeitet und verstehen kann. Nach einer Weile hat man
dann einen ganzen Stapel Vorgehensmuster, unter denen man dann bei einem neuen Problem einige
auswählen kann, die Effizienz beurteilen kann und das Problem löst, indem man aus seinem Erfah-
rungsschatz das Richtige auswählt.
Bereits beim Zusammenspiel zwischen Variablen und Schleifen zeigen sich die Probleme
vieler SchülerInnen11 im Umgang mit Steuerstrukturen. (Einfaches Beispiel: Wie bestimmt
man das Maximum aus fünf eingegebenen Zahlen?) 12 Ein grundsätzliches Dilemma des
Unterrichts besteht nun darin, dass häufig eine große Lücke zwischen dem passiven Beherr-
schen (also dem Nachvollziehen eines von der Lehrperson erstellten Programms) und dem
aktiven Beherrschen (also dem selbständigen Erkennen, wann und wie die jeweilige Steu-
erstruktur zur Problemlösung einzusetzen ist) klafft und dass diese Lücke nur sehr schwer
durch Erklärungen durch die Lehrperson zu überbrücken ist. 13
Und im Sinne dieses Zitates sollten sich Dozenten davor hüten, Lösungen zu Aufgaben an die Ler-
nenden auszugeben. Jeder Programmieranfänger sollte das schöne Gefühl kennenlernen, ein Problem
selbst gelöst zu haben. Und nur beim Durchdenken einer eigenen Lösung kann ein Neuling das Für und
Wider eines Lösungsansatzes bewerten.
11 Ganz ehrlich: ich war das nicht! Das große I“ ist im Originaltext, und bei dem Zitat muss ich das übernehmen.
12 ”
Übrigens in Python ein triviales Problem. Da in Python dynamische Parameterlisten für Funktionen zum Sprachumfang
gehören, liefert print(max(3,4,12,67,34,8)) das korrekte Ergebnis. Es ist Python völlig egal, wieviele Parameter
übergeben werden.
13 aus: <[Link]
BCr_den_Einsatz_im_Unterricht#Einleitung>
23
Teil I.
Grundlagen
25
1. Was ist Python?
Always look on the bright side of life
(Eric Idle 1 )
Wie Mark Lutz in seinem Buch Programming python“ 3 schreibt: You don’t have to run out and rent
” ”
The Meaning of Life or The Holy Grail to do useful work in Python, but it can’t hurt.“
Aus diesem Grund sollte sich niemand wundern, wenn typische Mustertexte in Python-Beispielen
Always look on the bright side of life“ oder And now for something completely different“ lauten. Es
” ”
fällt auf, dass Programmierer oft einen eigenen Sinn für Humor haben — besonders wenn sie Engländer
sind und Monty Python im Kopf haben.
1 Life of Brian
2 Bild lizensiert unter
3 [Programming Python], Seite 15
27
KAPITEL 1. WAS IST PYTHON? 1.2. WAS FÜR EINE SPRACHE?
28
KAPITEL 1. WAS IST PYTHON? 1.3. WARUM PYTHON UND NICHT EINE . . .
5. Python-Code ist im Verhältnis zu Java-Code relativ kurz, im Verhältnis zu perl-Code sehr klar.
Wie Lutz in [Programming Python], S. 4, schreibt, sind Python-Programme nur ein Fünftel bis ein
Drittel so lang wie Programme in C++ oder Java. Schau einfach noch mal zurück zum Vergleich
zwischen perl, Python und Java
Eine schöne Seite, die eine Idee davon gibt, was die Unterschiede der Programmiersprachen sind,
ist <[Link] Unter den Aufgaben sind ein paar klassische
Probleme in verschiedenen Sprachen gelöst. Es lohnt sich wirklich, hier zweimal hereinzuschauen.
Schau zum ersten Mal jetzt rein, und schau Dir speziell Probleme an, bei denen auch eine Lösung
in Python vorliegt. Vergleiche den Code (insbesondere die Länge des Codes) von Python mit dem
in anderen Sprachen. Ich empfehle für einen ersten Blick die Lösungen zu Prüfziffer auf Euro-
”
Banknoten“. Ein zweites Mal kann man dann auf diese Seite schauen, wenn man einen ersten
Eindruck von Python hat, denn dann sieht man, warum Lösungen in Python nicht nur besonders
kurz, sondern vor allem besonders elegant sind.
6. Als Folge davon ist Python schnell bei der Entwicklung und Erstellung von Programmen. Die
Kürze der Programme, die im vorigen Punkt angesprochen wurde, bewirkt, dass man oft keine
Klimmzüge machen muss, um ein Problem zu lösen.
7. Python ist freie Software. Es ist in den meisten Linux-Distributionen schon enthalten, zu Windows
frei aus dem Internet herunterzuladen. Das heißt, dass die (Weiter-)Entwicklung von Python nicht
von den finanziellen Interessen eines Unternehmens abhängt, sondern von den Bedürfnissen der
Nutzer, also der Programmierer. Oder anders gesagt: die Sprache bleibt so schön, wie sie ist, wenn
WIR es wollen.
8. Python-Programme können wie ganz normale Programme ausgeführt werden; es gibt aber auch
eine Test-/Entwicklungsumgebung, in der man Programm-Fragmente leicht und ohne großen
Aufwand testen kann. Außerdem kann man Python-Code interaktiv auf der Shell / Komman-
dozeile schreiben.
9. Python hat eine gute Datenbank-Schnittstelle.
10. Die meisten (alle?) Python-Distributionen haben schon eine grafische Bibliothek dabei, nämlich
Tkinter. Die hat den Vorteil, dass sie freie Software ist (ich weiß, ich wiederhole mich). Außer-
dem ist Tcl/Tk selbständig lauffähig, das heißt, man kann für die grafische Oberfläche eine Art
Prototyping“ machen und dann das erzeugte Fenster relativ einfach nach Tkinter umwandeln.
”
11. Seit kurzer Zeit ist ein weiterer wichtiger Punkt dazugekommen: der Raspberry Pi. Wer sich diesen
Zigarettenschachtel-PC kauft, will ihn auch bedienen. Der wird in Python programmiert.
(Womit ich es geschafft habe, von der seriösen Zahl 10 (10 Gebote ...) wegzukommen, und auf der
närrischen Zahl 11 gelandet bin. Geschrieben im Juli 2014, zu der Zeit der Monty Python Reunion Show.
)
Inzwischen habe ich von C. Severance das Buch Python for Informatics“ durchgeblättert. In seinem
”
Vorwort schreibt er:
In 2003 I started teaching at Olin College and I got to teach Python for the first time. The
contrast with Java was striking. Students struggled less, learned more, worked on more in-
teresting projects, and generally had a lot more fun.
29
KAPITEL 1. WAS IST PYTHON? 1.4. AUSFÜHRUNG VON . . .
Python wird nicht compiliert, sondern interpretiert. Das Programm, das Python-Quelltexte interpre-
tiert, heißt auch python (allerdings mit kleinem p“). Ein Interpreter“ liest einen Quelltext zeilenweise
” ”
und führt die Anweisung, die diese Zeile enthält, aus. Wenn Python auf dem Rechner installiert ist 8 ,
kann man diesen Interpreter sofort aufrufen.9 Das machen wir jetzt! Nachdem der Interpreter sich mit
7 Englisch wird dieses Wort und alle davon abgeleiteten natürlich mit c“ geschrieben, im Deutschen mit k“ aber im folgenden
” ”
Text wird es in beiden Formen auftauchen. Compiler“ sieht nur so, mit C“, genießbar aus!
8 ” ”
das heißt auch, dass die Pfade alle richtig gesetzt sind
9 Das gilt für Linux- und Mac-Systeme. Unter den Windows-Systemen muss unter Umständen zuerst die Position des Python-
Interpreters in die Umgebungsvariablen eingetragen werden.
30
KAPITEL 1. WAS IST PYTHON? 1.4. AUSFÜHRUNG VON . . .
dem Python-Prompt ( >>> ) arbeitsbereit gemeldet hat, geben wir dem Interpreter die erste Aufgabe:
Brav, der Interpreter hat die Zeile richtig gelesen und die Aufgabe zu unserer Zufriedenheit gelöst.
Was passiert aber, wenn wir etwas ganz anderes, weniger sinnvolles, schreiben, oder mit Monty Python
And now for something completely different“?
”
Beispiel 1.4.1 Hier fehlt eine korrekte Zuweisung!
>>> The Spanish Inquisition
File "<stdin>", line 1
The Spanish Inquisition
ˆ
SyntaxError: invalid syntax
Python beschwert sich hier, weil hier etwas auftaucht, was es nicht erwartet.10 Diese 3 Wörter gehören
nicht zum Sprachumfang von Python.
10 Wer Monty Pythons Flying Circus gesehen hat, weiß es: Nobody expects the Spanish Inquisition!“
”
31
2. Programmieren
33
KAPITEL 2. PROGRAMMIEREN 2.1. WAS HEISST PROGRAMMIEREN“?
”
34
KAPITEL 2. PROGRAMMIEREN 2.2. WAS IST ALSO EIN PROGRAMM?
Programmieren lehrt Lernen. Wo sonst kann ich Fehler machen, die zwar gleich bestraft werden (da-
durch, dass das Programm nicht läuft), aber die ich verbessern kann, ohne dass jemand anderer mich
deswegen tadelt. Dabei lerne ich, dass Lernen nicht nach dem ersten Versuch, ob erfolgreich oder nicht,
endet, sondern dass Lernen daraus besteht, etwas aufzunehmen, es anzuwenden, festzustellen, dass ich
es doch noch nicht beherrsche, und es dann nochmals zu versuchen.
Kapiert? Fehler sind in Ordnung!!! ... wenn man bereit ist, sie zu verbessern.8
1. Das in einer Programmiersprache geschriebene Programm, der sogenannte Quelltext oder auf
neudeutsch die Source, wird als ganzes in Maschinensprache umgewandelt. Dabei wird es auf
Syntaxfehler untersucht; im Falle, dass Syntaxfehler auftreten, wird die Umwandlung abgebro-
chen und eine Fehlermeldung ausgegeben.
Falls Programmcode aus anderen Quell-Dateien benutzt werden soll, wird dieser auch eingebun-
den. Das Ergebnis wird als Datei auf die Festplatte des Rechners geschrieben und liegt ab diesem
Zeitpunkt in Maschinensprache vor. Beim erneuten Aufruf des Programms wird diese Datei be-
nutzt.
Dieser Übersetzer wird Compiler genannt.
2. Das Programm, das als Quellcode vorliegt, wird Befehl für Befehl in Maschinensprache übersetzt
und ausgeführt. Das bedeutet insbesondere, dass auf die Festplatte des Rechners keine Datei mit
einem ausführbaren Programm geschrieben wird. Bei jedem erneuten Aufruf des Programms wird
der Quelltext wieder Zeile für Zeile abgearbeitet.
Ein Programm, das diese Arbeit verrichtet, wird Interpreter genannt.
Man kann es auch so beschreiben: nachdem ein Compiler den Quellcode in ein ausführbares Programm
umgewandelt hat, kann man dieses Programm immer wieder laufen lassen, ohne es neu zu kompilieren,
auf jeden Fall auf dem selben Computer, aber auch auf jedem Rechner mit dem selben Betriebssystem.
Ein interpretiertes Programm benötigt aber für jeden weiteren Programmlauf wieder den Interpreter,
um den Quellcode Zeile für Zeile in einen ausführbaren Befehl umzuwandeln.
35
KAPITEL 2. PROGRAMMIEREN 2.3. GESCHICHTE
Ausführen eines Algorithmus, so wie er durch den Programmcode vorgegeben ist und das Ausgabeme-
dium ist standardmäßig der Bildschirm.
2.3. Geschichte
Im Laufe der vergangenen 50 Jahre wurden viele solche formale Sprachen entworfen, meistens mit dem
Ziel, Probleme aus einem bestimmten Anwendungsbereich zu lösen. Zu diesen Programmiersprachen
wurden dann auch verschiedene Compiler entwickelt, verschiedene, weil es verschiedene Zielrechner
und damit verschiedene Maschinensprachen gibt, aber auch, weil es manchmal an einem Compiler
Verbesserungsmöglichkeiten gab, auch, weil handfeste wirtschaftliche Interessen dahinterstecken.
A NMERKUNG
Die Sprache COBOL wurde zum Beispiel entworfen, um vor allem administrati-
ve oder wirtschaftliche Probleme zu lösen, die Sprache Fortran, um technische,
mathematische oder naturwissenschaftliche Probleme zu bearbeiten, bei denen
es darauf ankam, große Mengen an Zahlen zu bearbeiten, die Sprache C ent-
stand, weil man eine Sprache benötigte, die sehr maschinennah arbeitet aber
trotzdem leicht zu programmieren ist. Dabei gilt, dass jede Programmiersprache
(mit Einschränkungen) alles kann, aber nicht alles gleich gut. Die wenigsten Pro-
grammierer hätten Spaß daran, Mathematik-Programme in COBOL zu schrei-
ben!!
Es gibt aber auch Programmiersprachen, die für eine breite Vielfalt von Problemstellungen geeignet
sind, die genausogut für die Verarbeitung von Zahlen wie für die Verarbeitung von Texten genommen
werden können. Welche Programmiersprache man lernt, und auch, welche Programmiersprache man
später hauptsächlich benutzt, hängt von den persönlichen Vorlieben ab: denen des Lehrers und später
den eigenen. Die erste Programmiersprache, die man lernt, sollte aber vor allem eines sein: leicht zu
erlernen.
9 hierzu sollte man sich das gute Buch von Grassmuck [Freie Software] besorgen, das — das Thema erfordert es ja schon — auch
fast frei“ ist, nämlich bei der Bundeszentrale für politische Bildung für einen geringen Unkostenbeitrag zu erhalten ist. siehe:
”
<[Link]>
10 [FSF]
11 Hat eigentlich schon einmal jemand untersucht, inwiefern Freibier die Entwicklung freier Software fördert?
36
KAPITEL 2. PROGRAMMIEREN 2.5. HILFSPROGRAMME
A NMERKUNG
So ist Python unter jedem gebräuchlichen Betriebssystem verfügbar. Linux-
Benutzer haben den Vorteil, dass Python zu fast jeder Distribution dazugehört
und meistens bei Standard-Installationen mitinstalliert wird, weil einige Program-
me unter Linux eben Python benötigen.
2.5. Hilfsprogramme
Als wichtigste Voraussetzung für das Programmieren wird ein Editor benötigt. Das ist KEIN Textverar-
beitungsprogramm. Open Office und Word und wie die Textverarbeitungsprogramme alle heißen sind
ungeeignet. Ein Editor soll keine Formatierungsanweisungen produzieren, sondern den Text genauso
speichern, wie ich ihn eingebe.
Wohl aber soll ein Editor die Strukturen einer Programmiersprache unterstützen. Die bei Windows
mitgelieferten Editoren (Wordpad, Editor) sind aus diesem Grund ungeeignet. Unter Unterstützung
einer Programmiersprache verstehe ich:
• Der Editor sollte bestimmte Konstrukte einer Sprache farblich hervorheben (englischer Fachaus-
druck: syntax highlighting)
• Der Editor sollte mehrere Dateien parallel geöffnet halten können. Du wirst es schnell merken,
dass es Deine Arbeit ungemein erleichtert, wenn Du im Editor Dein letztes Werk neben der aktu-
ellen Arbeit sehen kannst, denn meistens verwendest Du eine Technik, die beim letzten Programm
erfolgreich war, gleich noch einmal.
• Ein Editor sollte das Ordnunghalten unterstützen und, das ist bei Python besonders wichtig, die
vorgeschriebenen Ordnungskriterien beherrschen. Damit ist gemeint, dass der Editor automatisch
die zusammengehörigen Dinge als zusammengehörig sichtbar macht.
• Der Editor sollte automatische Wortvervollständigung beherrschen. Damit ist gemeint, dass der
Editor bei allen längeren Wörtern, die ich tippe, in seinem Gedächtnis kramt und einen sinnvollen
Vorschlag macht, wie das Wort jetzt zu Ende geschrieben wird. Das wird auch jeder schätzen,
wenn ein Programm einen gewissen Umfang erreicht. Und die Anwendung dieser Fähigkeit hilft
bei der Reduzierung der Fehlerzahl. Wenn ich eine Variable mindestAbnahme deklariert habe,
dann hilft es Tippfehler zu vermeiden, wenn ich nach den ersten 3 Buchstaben min“ schon den
”
Vorschlag destAbnahme“ bekomme. Wenn ich dieses Wort zehn Mal tippen müsste, dann würde
”
ich sicher den einen oder anderen Fehler machen.
Es gibt viele Editoren, die diese Bedingungen erfüllen und Open Source Software sind. Die sind meis-
tens von Programmierern für Programmierer gemacht — wirklich nicht die schlechteste Voraussetzung.
Da möge jeder sich seinen Lieblingseditor heraussuchen. Der beste Editor ist immer der, mit dem ich
selber gut auskomme.
Zwei Vorschläge mache ich trotzdem:
1. atom erfüllt diese Bedingungen, und wer seinen Editor nach seinen Bedürfnissen einrichten möchte,
liegt hier richtig. 13
2. SciTE (beachte die Groß-/Kleinschreibung) ist Open Source, und SciTE gibt es für Windows und
für Unix/Linux.
Ein Programm in einer Skriptsprache wie Python wird anfangs in einer Shell (für Windows-Benutzer:
auf der Kommandozeile) aufgerufen und macht seine Ausgaben genau dort. Deswegen sollte jeder die
12 , die ab jetzt einfach mit Windows bezeichnet werden, gleichgültig welcher Ausprägung (Windows XP, Vista etc.)
13 Nicht nur, wenn er programmieren will. Auch diesen Text in XML schreibe ich mit atom.
37
KAPITEL 2. PROGRAMMIEREN 2.6. VORAUSSETZUNGEN
wichtigsten Shell-Befehle (für Windows-Benutzer: die guten, alten DOS-Befehle) kennen und auch auf
der Shell sich im Verzeichnisbaum zurechtfinden.
Die nächste Stufe der Hilfsprogramme sind die Integrierten Entwicklungsumgebungen“, kurz IDE
”
(Integrated Development Environment). Hier existieren nebeneinander ein Editor, eine Shell, oft noch
ein Debugger und öfters noch andere Anwendungen unter einem Dach. Für Python bietet sich in erster
Linie Eric“ an, allerdings muss auf Windows noch eine Qt-Bibliothek installiert werden. Eine Alterna-
”
tive auf Windows ist der PyScripter, der auch Open Source ist. Eher spartanisch, aber für die Belange
eines Anfängers völlig ausreichend, ist die IDE geany“, natürlich auch Open Source.
”
2.6. Voraussetzungen
2.6.1. Das Dateisystem
Als Vorkenntnisse sollte man einiges über die Organisation des Dateisystems auf dem eigenen Rechner
wissen, nämlich was eine Datei, was ein Verzeichnis ist, wie man Verzeichnisse anlegt, Dateien kopiert,
umbenennt, verschiebt. Hilfreich ist, wenn man das nicht nur mittels einer grafischen Oberfläche14 kann,
sondern auch als Betriebssystem-Befehl (also unter Linux auf einer shell und unter Windows auf der
Kommandozeile). Aber das ist wahrscheinlich im 21. Jahrhundert zuviel verlangt. Mark Lutz schreibt in
einer Fußnote seines Buches [Programming Python] auf Seite 266,
In the first edition of the book Learning Python, for example, my coauthor and I directed
readers to do things like open a file in your favourite text editor“ and start up a DOS
” ”
command console“. We had no shortage of email from beginners wondering what in the
world we meant.
Dem ist fast nichts hinzuzufügen. Oder doch? Eine Frage sei erlaubt: Warum richten sich Dozenten,
Lehrer, Didaktiker nach dem, was große Konzerne propagieren, nämlich, dass man Computer bedienen
kann, ohne zu verstehen, was man da tut und warum legen sie nicht mehr Wert darauf, dass Prinzipien
des Computers verstanden werden, bevor man mit einer schönen grafischen Oberfläche herumspielt?
Also muss man sich (oder als Dozent: den Lernenden) zuerst einmal klarmachen, dass das, was man
in einen Editor oder in eine Entwicklungsumgebung eingibt, erst dann im Rechner“ ist, wenn man es
”
in einer Datei gespeichert hat. Zum Glück bieten sowohl Editoren als auch Entwicklungsumgebungen
hier Icons an, mit Hilfe derer man diese Operationen durchführen kann. Nach dem Anwählen dieser
Icons öffnet sich in der Regel ein Fenster, in dem man
die Datei gespeichert werden soll. Zum zweiten Punkt folgt gleich noch ein eigenes Unterkapitel. Hier
soll allerdings schon auf die Eigenart eines Software-Konzerns von der Westküste der USA eingegan-
gen werden. Die Entwickler, die für diesen Konzern ein Betriebssystem“ entworfen haben, meinen seit
”
einigen Jahren, dass sie wissen, was wir, die Benutzer wollen. So ist unter diesem Betriebssystem stan-
dardmäßig eingestellt, dass in allen Dateisystem-Betrachtern, also auch bei dem, der beim Speichern
einer Datei aufgerufen wird, bekannte Dateiendungen“ nicht angezeigt werden. Das führt oft zu uner-
”
warteten Schwierigkeiten und ungeahnten Ergebnissen.
A CHTUNG
Wer unter Windows ernsthaft arbeiten will, sollte sich von Microsoft nicht bevor-
munden lassen und sofort den Schalter umlegen, um grundsätzlich alle Dateien-
dungen anzeigen zu lassen.
14 Glück gehabt! Das [dummdeutsch]e Wort Benutzeroberfläche“ konnte ich im Text gerade noch vermeiden. Der Benutzer bin
”
ich, meine Oberfläche nenne ich Haut, und was die auf einem Computer-Bildschirm soll, habe ich noch nie verstehen können.
38
KAPITEL 2. PROGRAMMIEREN 2.6. VORAUSSETZUNGEN
A CHTUNG
Wer unter Windows die IDE pyscripter“ benutzt, merkt es sehr schnell, dass er
”
Leerzeichen in Dateinamen hat: das Programm hängt sich auf.
Das im vorigen Absatz Gesagte gilt auch für Verzeichnisnamen. Auch hier haben Sonderzeichen und
Leerzeichen nichts zu suchen.
2.6.3. Datei-Operationen
Falls man die nötigen Befehle des Betriebssystems nicht beherrscht, sollte man sich ein Handbuch neh-
men und nachschlagen, wie man unter seinem Betriebssystem
Ohne den Anspruch der Vollständigkeit gebe ich hier die Befehle, die für die oben aufgelisteten Ope-
ration benutzt werden, unter Unix-artigen Betriebssystemen und unter Windows in einer Tabelle wieder.
15 also
der Einstellung der Sprache der Darstellung
16 Einen Link auf eine Datei anzulegen bedeutet, dass die Datei nur einmal existiert, aber unter verschiedenen Namen angespro-
chen werden kann. Das erscheint sinnlos? Ist es aber nicht. Mit Name“ ist dabei natürlich der voll-qualifizierte Name gemeint,
”
d.h. dass vor allem in einem Verzeichnis die reale“ Datei existiert, in einem anderen Verzeichnis nur der Link, der Verweis
”
auf die Originaldatei.
39
KAPITEL 2. PROGRAMMIEREN 2.7. WAS HEISST PROGRAMMIEREN“? . . .
”
—David Evans17
Programmieren heißt erst einmal, Befehle (Anweisungen, oft auch mit dem englischen Wort statements
bezeichnet) zu schreiben, die der Computer mit Hilfe von Python (oder einer anderen Programmierspra-
che) versteht und ausführen kann. Aber warum soll der Computer das machen? Erstens: er kann vieles
schneller als ich. Zweitens: ihm wird nicht so schnell langweilig wie mir. Drittens: auch nach Stunden
wird er nicht müde und macht deswegen keine Leichtsinnsfehler.
—unbekannt
Gerade im Hinblick auf Programmieranfänger, vor allem Schüler, wurde die objektorientierte Pro-
grammierung als die Errungenschaft gefeiert, die einen intuitiveren Zugang zur Programmierung ver-
schafft und so die Einstiegshürden senkt. Leider wurde dabei übersehen, dass das beste (objektorientier-
te) Paradigma nichts nützt, wenn Lernende nicht wissen, was an der Basis passiert: was eine Variable
ist, was WENN - DANN“ bedeutet, was eine Wiederholung ist und vieles mehr. Nein, das ist noch
”
nicht die Basis: dazu gehört auch, dass man weiß, was Bedingungen sind und wie man diese formuliert,
wie man einer Variablen einen Wert zuweist, wie eine Wiederholung beendet wird usw.
Lehrer, die an Schulen unterrichten, wissen, was ich meine. Da wird etwa in der Mittelstufe ein
schlichtes Anwendungsprogramm zur Tabellenkalkulation benutzt, und man muss froh sein, wenn die
Schüler mit viel Anleitung verstehen, wie man darin die WENN-DANN“-Funktion benutzt. Und jeder
”
Lehrer weiß, wieviel davon im darauffolgenden Schuljahr noch vorhanden ist.
Ich bin überzeugt, dass der Einstieg in die (objektorientierte) Programmierung nicht geht, wenn man
nicht die oben beschriebenen Grundlagen beherrscht: wenn man nicht die elementaren Regeln der struk-
turierten Programmierung gelernt hat. Und so ist dieses Buch auch aufgebaut: die Objektorientierung
kommt ziemlich weit hinten.
Die langweiligste Art der Programmierung ist die, dass man einem Rechner die Aufforderung gibt,
zehn oder hundert oder tausend verschiedene Befehle nacheinander auszuführen. So etwas wird eine
Sequenz genannt. Das bedeutet, dass ich dem Rechner erst einmal diese vielen Befehle aufschreiben
muss. Die meisten von uns würden das als völlig uneffektiv ablehnen, denn in der Zeit, in der wir die
Befehle aufgeschrieben hätten, hätten wir das Problem schon zu Fuß“ gelöst.
”
In der Frühzeit der Datenverarbeitung war das allerdings ein übliches Vorgehen. Es gab verhältnismäßig
wenige Rechner und relativ viele Benutzer, es gab wenige Eingabegeräte und wenige Ausgabegeräte.
Also habe ich meine Befehle aufgeschrieben, irgendwann in der Nacht hat ein freundlicher Mitarbei-
ter des Rechenzentrums meine Befehle dem Computer zum Fressen gegeben und am nächsten Morgen
konnte ich das Ergebnis abholen.
Interessanter ist es da schon, den selben Befehl tausendmal ausführen zu lassen. Das ist doch schon
eine ganz schöne Zeitersparnis: ich schreibe einen Befehl auf und weise meinen Rechenknecht an, das
doch bitte 3000mal zu machen.18 Dies wird in der Datenverarbeitung eine Schleife, mit einem Fremd-
wort Iteration, genannt.
Es ist auch interessanter für uns, wenn wir dem Rechner überlassen können, was er macht, zum
Beispiel in allen Dateien, in denen sowohl das Wort Salat“ als auch das Wort Gurke“ auftaucht, die
” ”
Gurke durch eine Salatgurke zu ersetzen, in allen anderen die Gurke durch eine Gewürzgurke. Der
Rechner (das Programm) steht also vor der Alternative: entscheide mal, ob das eine Salatgurke oder
17 aus: [Evans], S. 35
18 Denken wir an unsere Schulzeit zurück und die Strafarbeit: Du schreibst jetzt 100mal Ich soll meinen Nachbarn nicht mit der
”
Stecknadel pieksen.“
40
KAPITEL 2. PROGRAMMIEREN 2.7. WAS HEISST PROGRAMMIEREN“? . . .
”
eine Gewürzgurke ist, aber bitte intelligent! Diese Entscheidung wird in der Programmierung eine Al-
ternative genannt.
Das sind also die Elemente der strukturierten Programmierung:
• die Sequenz
• die Alternative
• die Iteration
A NMERKUNG
Soll ein Programm-Quelltext (in Python) Kommentare enthalten? Allgemein gilt:
den Programm-Quelltext sollte nicht nur ich, der Schreiber, auch noch nach eini-
gen Monaten oder Jahren verstehen können, sondern auch ein eventueller Le-
ser, der etwas an dem Programm ergänzen oder verbessern möchte. Hilfreich
dabei ist natürlich, dass man die Variablen, grundsätzlich alle Bezeichner, mit
Namen versieht, die auf die Bedeutung verweisen. Natürlich könnte man bei-
spielsweise in einem Programm zur Berechnung von Größen in rechtwinkligen
Dreiecken die Variablen so benennen: Gandhi, Hilde und Schatzi Aber ob
dadurch der folgende Quelltext besonders verständlich wäre, ist doch zu be-
zweifeln: Schatzi = Gandhi / Hilde Etwas besser wäre schon die Benennung
gegenkathete, hypotenuse und sinus womit das obige Programmfragment
zu sinus = gegenkathete / hypotenuse wird und damit doch verständlicher.
Trotzdem: auch so würde das wahrscheinlich kein Programmierer schreiben,
denn diese Spezies Menschen zeichnet sich durch Faulheit aus, und selbst bei
Editoren, die automatische Wort-Ergänzung beherrschen, ist das für viele Pro-
grammierer zu viel Schreibarbeit, weswegen man eher etwas fände wie sin =
gegenk / hyp
Manchmal ist es aber hilfreich, wenn man im Quelltext eine kurze Erläuterung fin-
det, was die Variable für eine Bedeutung hat. Mathematiker speziell — das sind
in der Regel noch faulere Menschen als Programmierer — benennen Zähler
grundsätzlich mit i, wenn sie einen weiteren Zähler brauchen, heißt der i2
und das Optimum an Kreativität ist der Name j für einen weiteren Zähler. Ein
häufiges Problem in der Informatik ist es, eine Matrix zu durchsuchen. Dazu
benötigt man in der Regel zwei Zähler, einen für die Zeilen, einen für die Spal-
ten. Also, pfiffig wie Programmierer sind, werden diese beiden Zähler zz und sz
benannt. In einem Quelltext ist es dann durchaus sinnvoll, dass man dazu einen
Kommentar schreibt. Kommentare werden durch einen Lattenzaun (#) eingelei-
tet. Alles von diesem # bis zum Zeilenende wird von Python ignoriert und ist nur
für die Augen eines eventuellen Lesers bestimmt:
Eine besonders hilfreiche Eigenschaft von Kommentaren in Python ist, dass man damit eine einfache
Hilfe-Funktion für zum Beispiel eine Funktion schreiben kann. Der Hilfetext wird in die dreifachen
Anführungszeichen an den Anfang der zu beschreibenden Funktion geschrieben.
41
KAPITEL 2. PROGRAMMIEREN 2.8. OBJEKTORIENTIERUNG
1. Mit help(quadrate) wird ein gegliederter Hilfetext ausgegeben. Das sieht so aus:
quadrate(zahl)
Der Funktion quadrate wird als
Parameter eine Zahl mitgegeben,
die Funktion liefert das Quadrat der
Zahl zurück
2. Mit der print-Funktion, indem man den Namen der Funktion, gefolgt von zwei Unterstrichen,
gefolgt vom Text doc, gefolgt von nochmals zwei Unterstrichen eingibt.
Die print-Funktion wird erst weiter hinten angesprochen, aber es ist wahrscheinlich klar, was sie macht:
sie gibt etwas aus, in diesem Fall auf den Bildschirm.
Und die Funktion funktioniert so wie gewünscht:
2.8. Objektorientierung
Dieses Kapitel greift vor: über Objektorientierung wird erst wieder im Kapitel Klassen gesprochen. Aber
bereits in den Kapiteln zuvor wird immer wieder eine Notation benutzt, die aus dem Bereich der Ob-
jektorientierung stammt.
42
KAPITEL 2. PROGRAMMIEREN 2.9. PROGRAMMIERSTIL UND . . .
In (fast) allen Programmiersprachen muss man beim Anlegen einer Variablen angeben, welchen Typ
diese Variable hat. Man muss etwa festlegen, dass die Variable zahl1 eine Variable des Typs int ist,
wobei int die Abkürzung für das englische Wort für ganze Zahl“ nämlich integer ist; oder eine
”
vorname soll vom Typ string sein, also eine Zeichenkette zum Inhalt haben.
In Python muss das nicht festgelegt werden. Bei der ersten Wertzuweisung an eine Variable merkt Py-
thon selbst, zu welcher Klasse (gemerkt? nicht zu welchem Typ) diese Variable gehört. Klassen sind Mo-
delle für Variablen, die nicht nur bestimmte Eigenschaften haben, sondern auch festgelegte Fähigkeiten;
das heißt, dass durch die Klassenzugehörigkeit einer Variablen festgelegt wird, was diese Variable kann
und darf.
Die Eigenschaften bzw. die Fähigkeiten einer Variablen, also eines Objektes einer Klasse, werden
durch einen Punkt an den Namen der Variablen angehängt. Ein Beispiel: wenn ich also eine Variable
mit Namen name habe, die den Wert Meier“ enthält, ist dies ein Text, und dieser Text hat die Fähigkeit,
”
sich selber in reinen Großbuchstaben schreiben zu lassen:
Fähigkeiten sind Funktionen, und die Schreibweise ähnelt auch der Schreibweise einer Funktion in
der Mathematik: hinter den Funktionsnamen wird dort in Klammern die Variable der Funktion angege-
ben. Das ist hier auch so, aber die Funktion upper benötigt keine Variable, also bleibt hier die Klammer
leer.
—David Evans19
Solange man an seinem eigenen Rechner sitzt und nur für das eigene Vergnügen programmiert, kann
man das machen, wie man will. Viele Programmierer sind auf diese Art groß geworden. Wenn man
aber aus seinem stillen Kämmerlein herauskommt, wird das eigene Werk auf einmal kritisch beäugt.
Und das ist gut so. Auch wenn D. Knuth sein Werk The Art of Computer Programming“ genannt hat,
”
sollte man sich nicht zuviel künstlerische Freiheiten herausnehmen— vor allem dann, wenn man unter
künstlerischer Freiheit hauptsächlich Chaos und Unordnung versteht. Jede Kunst besitzt auch Struktur.
Struktur entsteht, indem man das Handwerkszeug beherrscht, das für die Beherrschung der Kunst(-
richtung) nötig ist. So sollte man sich nach den ersten paar Programmen diese noch einmal anschauen
und sich die Variablennamen vornehmen: sind die alle nach einer Regel (die ich mir selber gegeben
habe und in Worte fassen kann) aufgebaut? Oder gibt es da Inkonsistenzen in der Schreibweise? Sind
logische Zusammenhänge durch die Schreibweisen sichtbar gemacht?
Viele der Bemerkungen, die in Büchern zu anderen Programmiersprachen gemacht werden, sind in
Python zum Glück überflüssig. Ordnung (und damit ein guter Programmierstil) ergibt sich in Python
19 aus: [Evans], S. 35
43
KAPITEL 2. PROGRAMMIEREN 2.9. PROGRAMMIERSTIL UND . . .
automatisch durch das Prinzip der Einrückung. So wie in jedem Text einer natürlichen Sprache wie
Deutsch ist der Leser froh, wenn er auf einen Blick erkennt, was zusammenhängt. Der Autor benutzt zu
diesem Zwecke die altbekannten Mittel der Gliederung: Kapitel, Absätze, Sätze, Satzteile.
In Python ist Einrückung nicht eine Möglichkeit, sondern eine Pflicht. Was zusammengehört, muss
auf der selben Einrückungsstufe stehen. Wer schon einmal einen Programmierkurs gegeben hat, weiß
das sehr zu schätzen. Jeder weiß, dass Anfänger des Programmierens, wenn sie nicht müssen, oft schnell
etwas hinschreiben, ohne sich eine Struktur zu überlegen. Das kann dann in einer Sprache wie perl so
aussehen:
Beispiel 2.9.1 Schlechter Stil! So nicht!! (Das ist auch nicht Python)
#!/usr/bin/perl
$caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";$kls = "abcdefghijklmnopqrstuvwxyz";
$gesamt = 0;
$zeile = <STDIN>;
chomp $zeile;
foreach $j(0..25) {$anz[$j] = 0;}
open(AUS,">[Link]");
print AUS "Buchstaben insgesamt: $gesamt\n";
print AUS "Buchstabe absolut relativ\n";
foreach $j(0..25) {
print AUS " ".substr($caps,$j,1)." : ".
$anz[$j]." ".$anz[$j]/$gesamt."\n";}close AUS;
exit 0;
Das sieht aus, wie wenn es ohne Punkt und Komma geschrieben wäre.20 Dieses perl-Programm ist
lauffähig. 21 Aber wirklich nicht gut lesbar. Eine Gliederung ist nicht zu erkennen. In Python ginge so
etwas nicht!
20 Ist es auch. Die Gliederungsmerkmale sind die Strichpunkte und die geschweiften Klammern.
21 Perl: The only language that looks the same before and after RSA encryption. – Keith Bostic
44
KAPITEL 2. PROGRAMMIEREN 2.10. RESERVIERTE WÖRTER
A NMERKUNG
In jedem Unternehmen gibt es heutzutage etwas wie eine corporate identity“. In
”
jeder EDV-Abteilung mit Programmierern gibt es dafür eine Sammlung von Kon-
ventionen. Da wird dann etwa festgelegt, oder dass Variablennamen immer mit
einem Kleinbuchstaben anfangen, oder dass der Variablenname von Variablen,
die eine Zahl zum Inhalt haben, immer mit z “ anfangen. Jede dieser Sammlun-
”
gen von Richtlinien kann unterschiedlich sein, jede hat aber ihre Berechtigung.
Für sich selber als Anfänger der Programmierung sollte man solche Richtlinien
auch aufstellen und sich daran halten. Es hilft!
Für Python gibt es auch eine solche Richtlinie. Man findet sie unter PEP 8
<[Link]
Wir, die Programmierer, erweitern durch unsere Programme das Vokabular, indem wir neue Vokabeln
für neue Sachverhalte erfinden.
45
KAPITEL 2. PROGRAMMIEREN 2.12. ... UND DAS FEHLT
Wie in jeder natürlichen Sprache auch kann man in einer Programmiersprache etwas richtig aus-
drücken mit dem Ergebnis, dass der Empfänger das versteht; man kann aber auch etwas fehlerhaft
ausdrücken, was zur Folge hat, dass der Empfänger nichts versteht. In einer Programmiersprache ist
der Empfänger der Interpreter oder der Compiler.
Die Reaktion des Empfängers ist aber sehr unterschiedlich. In einer Nachricht, die in einer natürlichen
Sprache vom Sender zum Empfänger geht, versucht der Empfänger auch bei Fehlern noch den Inhalt
der Nachricht zu verstehen, im Zweifelsfall dadurch, dass er den Sender um Bestätigung der Interpre-
tation bittet. In einer Programmiersprache ist die Reaktion eindeutig: der Compiler bzw. der Interpreter
beendet seine Arbeit einfach dadurch, dass er meldet: mit dem Geschriebenen kann ich nichts anfangen,
weil es einen oder mehrere Fehler enthält.
Das ist für den Schreiber zuerst mal sehr enttäuschend. Und dann ist es mit Arbeit verbunden, denn
jetzt muss der Schreiber seinen Text auf mögliche Fehler untersuchen. Bevor ich auf die einzelnen Arten
von Fehlern eingehe muss ich aber hier eine allgemeine Bemerkung machen.
Zu Beginn des 21. Jahrhunderts ist das Unterrichten von Programmierung, ganz unabhängig von der
Programmiersprache, wesentlich schwieriger als in den 70er-Jahren des 20. Jahrhunderts. Der Grund ist
ganz einfach: kaum jemand kann heute noch richtig schreiben. Besonders schwierig ist das Unterrich-
ten in Programmierung an der Schule, denn korrektes Schreiben ist leider überhaupt nicht mehr nötig,
um einen Schulabschluß zu erhalten, nicht einmal mehr im Abitur. Das schöne Wort Verbesserung“ ist
”
sowieso aus dem Wortschatz jedes (Deutsch-)Lehrers verschwunden nach dem Motto: das tu ich mir
”
doch nicht an, dass ich den Quatsch ein zweites Mal lese“, weswegen Schüler dieses Wort und die damit
verbundene Tätigkeit nicht mehr kennen. Ein Beispiel aus einer durchschnittlichen 12. Klasse: in einem
Programm sollte eine Funktion erhöhen“ geschrieben werden. Die verschiedenen Schreibweisen für
”
das Wort erhöhen“ variierten je nach Schüler von 2 bis 4 (erhoeen, erhöen, errhöhn, erhoehn . . . ). Auf-
”
gefordert, den Programmtext nochmals zu lesen, war die Antwort meistens: Das hab ich schon gemacht,
da seh ich keinen Fehler.
Was also in einem Aufsatz die Note 2-3 ergibt, führt in der Programmierung zur Note 6.
Jetzt also zu den verschiedenen Arten von Fehlern:
• Syntax-Fehler. In der deutschen Sprache gelten etwa die Syntax-Regeln, dass ein Satz mit einem
Großbuchstaben beginnt und mit einem Satzzeichen (Punkt, Ausrufezeichen, Fragezeichen) en-
det. In jeder Programmiersprache gibt es ähnlich einfache Syntax-Regeln. Fehler in der Syntax
sind die am einfachsten zu findenden Fehler (sollte man meinen; siehe aber dazu nochmals den
vorhergehenden Absatz). In einer natürlichen Sprache sind Syntaxfehler noch kein Hindernis für
eine funktionierende Kommunikation. In einer Programmiersprache ist der Unterschied der von
einem lauffähigen Programm zu . . . nix. Ein Stück Programmcode mit Syntaxfehlern ist nix.
• Semantische Fehler. Diese Fehler sind gekennzeichnet durch syntaktisch korrekte Anweisungen
in einem Programm. Verglichen mit einer natürlichen Sprache bedeutet das, dass die einzelnen
Sätze in dem kommunizierten Text korrekt sind. Trotzdem macht das Programm nicht das, was es
soll. Der Text ergibt keinen Sinn (oder nicht den erwarteten Sinn). Semantische Fehler sind nicht
immer leicht zu finden, selten durch Probieren, Umkodieren, Ändern von Programmen. Leichter
findet man solchen Fehler, wenn man sich vom Rechner löst und das Problem neu durchdenkt.
• Laufzeitfehler. Wie der Name schon sagt, treten solche Fehler erst bei der Ausführung des Pro-
gramms auf. Syntax und Semantik scheinen in Ordnung, aber das Programm bricht aus irgend-
einem (auf den ersten Blick unerklärlichen) Grund ab. Ein typisches Beispiel ist, dass man im
Programm codiert hat, dass etwas an der 5. Stelle (von irgendetwas) gelesen werden soll. Das
irgendetwas“ hat aber nur 3 Stellen.
”
46
KAPITEL 2. PROGRAMMIEREN 2.13. FEHLER FINDEN
• exaktem Lesen
• gründlichem Nachdenken
Vor allem bei den Übungsprogrammen, die ja selten mal länger als 50 oder 100 Zeilen sind, ist der
Aufwand überschaubar, und scharfes Hinschauen und Nachdenken hilft hier. Aber bei längeren Pro-
grammen ist man dankbar für eine Hilfe, aus historischen Gründen debugger“ genannt. Ein Debugger
”
erlaubt es, die Ausführung eines Programmes an einer beliebigen Stelle zu unterbrechen und den Inhalt
der Variablen zu diesem Zeitpunkt anzuschauen. Für viele Programmiersprachen und in vielen IDE’s
(siehe nächstes Kapitel) existieren Debugger. Auch das sollte sich ein Programmieranfänger einmal an-
schauen, wenn er eine IDE auswählt: die IDE ist die beste, die mir am besten gefällt.
Die Hardcore“-Programmierer verschmähen natürlich einen Debugger. Okay, in Wirklichkeit tun sie
”
es nicht, aber ihr Debugger heißt print! Das, was ich im vorigen Absatz geschrieben habe, erledigen sie
durch die Ausgabe von Variablen-Inhalten mittels der print-Anweisung . . . und haben dadurch einen
Minimal-Debugger.
2.14. Aufgaben
1. Lies diagonal über die Python-Seite im WWW: <[Link] (Gewöhne Dich
gleich daran: in der Informatik ist vieles nur auf Englisch zu finden!)
2. Wenn Du Kinderbücher magst: schau Dir mal Snake Wrangling for Kids“ an. Das gibt es in einer
”
deutschen Übersetzung unter <[Link]
47
Teil II.
IDE
49
3. Die Entwicklungsumgebung IDLE: Zahlen
und Variable
Die fast wichtigste Regel, wenn man sich ans Programmieren begibt, kommt natürlich hier auch als
erstes: Erst denken, dann tippen
Das hört sich einfach an und selbstverständlich, aber viele, auch erfahrene Programmierer lesen ei-
ne Aufgabenstellung, setzen sich an die Tastatur und fangen an zu schreiben. Dann ist das Programm
fertig, und der Programmierer stellt fest: ist das umständlich geschrieben, ist das unschön, das geht doch
verständlicher. Es ist wie beim Aufsatzschreiben: ein gutes Konzept macht das eigene Werk übersichtlicher,
verständlicher und meistens auch kürzer.
Die zweite Regel ist fast genauso wichtig: Ein Programm ist erst fertig, wenn es ausreichend getestet
ist.
Und dann hast Du das Programm geschrieben, hast es einmal gestartet und es hat funktioniert, wie Du
Dir das vorgestellt hast. Also legst Du die Füße hoch, freust Dich, dass Du mit Deiner Arbeit fertig bist
und gibst das Ergebnis Deinem Chef (wenn programmieren Dein Job ist) oder Deinem Lehrer (wenn
Du Schüler oder Student oder sonst irgend ein Lernender bist und das eine Hausaufgabe oder eine
Prüfungsaufgabe war). Der Chef (oder Lehrer) startet das Programm, und es tut sich nichts (oder etwas
ganz unerwartetes).
Denn Du als Programmierer hast vergessen, dass derjenige, der das Programm anwendet (oder überprüft)
leider nicht genau die Daten eingibt, die Du eingegeben hast und mit anderen Daten läuft das Programm
überhaupt nicht.
Eine Entwicklungsumgebung, auf englisch Integrated Development Environment, wird mit IDE abgekürzt.
Da ist es kein Zufall, dass die Entwicklungsumgebung von Python idle heißt. Zum einen, weil idle ja
ein schönes englisches Wort ist, dessen Bedeutung Mathematikern und Programmierern zum Prinzip
geworden ist, zum anderen weil der fröhliche Mensch auf dem Bild, wie allen Freunden des Leben des
”
Brian“ bekannt, Eric Idle heißt. 2
51
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
Rufen wir also einfach mal IDLE auf! Der Bildschirm von IDLE sieht so aus!
Jetzt geben wir einfach mal etwas in IDLE ein, in Erinnerung dessen, dass ein Computer ein Rechner
ist, eine komplizierte Mathematik-Aufgabe. Zuerst müssen den Variablen, hier der Einfachheit halber
x1 und x2 genannt, Werte zugewiesen werden. Der Zuweisungsoperator in Python ist das Gleichheits-
zeichen.
>>> x1 = 3
>>> x2 = 4
>>> ergebnis = x1 + x2
Jede einzelne Zeile, die wir oben geschrieben haben, ist eine Anweisung (oder ein Befehl) in Python.
Manchmal wird dafür auch das englische Wort statement“ benutzt. Damit wird Python gesagt: mach
”
52
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
dies, mach das. Die obigen 3 Zeilen geben Python genau 3 Befehle, und diese Befehle heißen in mensch-
licher Sprache:
1. Gib einem Speicherplatz den Namen x1 und weise diesem Speicherplatz den Wert 3 zu.
2. Gib einem anderen Speicherplatz den Namen x2 und weise diesem Speicherplatz den Wert 4 zu.
3. Gib einem weiteren Speicherplatz den Namen ergebnis und weise diesem Speicherplatz die
Summe der Werte zu, die auf den Speicherplätzen mit den Namen x1 und x2 gespeichert sind.
Das ist jeweils eine sehr umständliche Sprech- und Schreibweise. Man drückt das deswegen oft einfa-
cher aus durch:
Es ist wohl fast selbstverständlich, wie eine Anweisung abgearbeitet wird: von links nach rechts;
dabei gelten aber die Regeln, die aus der Mathematik bekannt sind: was in Klammern steht, wird zuerst
verwertet, danach kommen (im Falle von mathematischen Anweisungen) die Punkt-“Rechnungen,
”
dann die Strich-“Rechnungen.
”
A NMERKUNG
Wer sich für diese schrittweise Ausführung von Befehlen interessiert, aber auch
für alle Anfänger, für die das oben beschriebene völliges Neuland ist: es gibt eine
nette Entwicklungsumgebung mit Namen thonny, die genau das macht. Diese
IDE ist auch freie Software und existiert wohl für alle Betriebssysteme.
Im Menu unter Run -> Debug(Nicer) werden die einzelnen Aktionen von
Python Schritt für Schritt angezeigt.
Nachdem wir unser erstes Python-Programm geschrieben haben, werden wir mutig bis übermütig.
Lassen wir den Rechner rechnen! Die arithmetischen Operatoren sehen vertraut aus, zwar nicht so, wie
man sie mit der Hand schreibt, sondern so wie man sie auf der Computer-Tastatur sieht.
• Addition 6 + 3
• Subtraktion 6 - 3
• Multiplikation 6 * 3
• Division 6 / 3
• Exponentiation 2**3
53
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
Das ist der passende Zeitpunkt, um in IDLE ein bißchen herumzuspielen und ein paar Rechnungen
ausführen zu lassen. Und vielleicht ist das auch ein Grund, immer IDLE laufen zu lassen. 3
1. In der ersten steht die Version des Python-Interpreters. Hier ist es Version 3.6.5. Die Division von
9 durch 3 ergibt 3.0 Das Ergebnis einer Division ist immer eine Division.
2. Die ganzzahlige Division, die als Ergebnis auch eine ganze Zahl liefert und diese beim Dezimal-
komma abschneidet wird durch den doppelten Schrägstrich erledigt. (Wie damals in der Grund-
schule: 9 : 4 = 2 (Rest 1))
In Python 2 sähe das etwas anders aus. Die Division von 9 durch 3 ergibt hier das Ergebnis 3 (als
ganze Zahl). Also stellen wir hier einen gravierenden Unterschied zwischen Python 2.x und Python 3.x
fest. Das stelle ich hier in einer Tabelle gegenüber:
3 Wer unter Linux / KDE arbeitet, weiß die Möglichkeit von virtuellen Bildschirmen zu schätzen und wird sich wahrscheinlich
jetzt schon längst einen virtuellen Bildschirm eingerichtet haben, auf dem nur IDLE läuft.
Und wer unter Windows arbeitet, weiß vielleicht gar nicht, wie komfortabel grafische Oberflächen sein können!!!
54
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
Wenn wir einer Variablen einen Wert zuweisen, kann es passieren, dass wir sehr bald nicht mehr
wissen, ob wir eine ganze Zahl oder eine Dezimalzahl zugewiesen haben. Das können wir in Python
aber leicht rauskriegen.
Und manchmal ist es nötig, eine Variable, die den Typ int hat, in den Typ float umzuwandeln,
oder umgekehrt.
Eine wichtige Kleinigkeit muss an dieser Stelle festgehalten werden: die Grundlage bei der Entwick-
lung von Python (wie von fast allen Programmiersprachen) ist englisch, also gibt es kein Dezimalkom-
55
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
A NMERKUNG
In Python 3 ist die Division (ausgeführt durch den Schrägstrich /) immer
eine Fließkomma-Division. Wenn man in Python 3 eine Ganzzahl-Division
durchführen will, also eine Division, bei der das Ergebnis eine ganze Zahl ist,
muss man den Doppel-Schrägstrich // benutzen.
eingeben.
Ebenso gilt:
>>> x1 = 3
>>> x2 = 4
>>> ergebnis = x2 / x1
>>> ergebnis
1.3333333333
Für die Division, wie sie in der Grundschule gelernt wird, nämlich
4 : 3 = 1 (Rest 1)
>>> 4 // 3
1
Es gibt aber wirklich viele Anwendungen, bei denen man genau das will, und dazu will man noch
den Rest berechnet haben. Dazu gibt es den Rest-Operator, korrekt Modulus genannt. Wir geben also
ein, um das zu testen:
und das liefert uns den Rest 2 bei der Division von 8 durch 3.
Das, was wir im vorigen Absatz Python vorgeworfen haben, ist kein Befehl. Es ist ein Ausdruck, auf
englisch eine expression“. Auf der Python-Konsole, im Python-Interpreter, kann man auch Ausdrücke
”
auswerten lassen, ohne einen Befehl auszuführen. Das macht man manchmal, um zu testen, welchen
56
KAPITEL 3. DIE . . . 3.2. RECHNEN IN DER . . .
Wert ein Ausdruck hat. Allerdings ist der Wert des Ausdrucks sofort verloren, wenn ich etwas anderes
mache, da er nicht gespeichert wird, nicht ausgegeben wird ... Deswegen lasse ich Ausdrücke so gut es
geht weg.
Python bietet uns sogar noch mehr:
liefert als Ausgabe ein Paar von Zahlen, wobei die erste Zahl das ganzzahlige Ergebnis von 13 / 3 ist,
die zweite Zahl der Rest bei dieser Division. Dieses Paar ist ordentlich in Klammern geschrieben, und
das soll an dieser Stelle uns erst einmal nur erfreuen. Was diese Schreibweise genau bedeutet, folgt in
einem späteren Kapitel.
Bisher haben wir Berechnungen durchgeführt und das Ergebnis der Rechnung implizit ausgeben las-
sen, das heißt, wir haben Python nicht ausdrücklich angewiesen, etwas auszugeben. Der Befehl, um
etwas an den Bildschirm auszugeben, lautet print.
print nimmt die Argumente, die in der Klammer stehen, wandelt jedes einzelne in eine Zeichenket-
te (einen String) um, setzt die einzelnen Zeichenketten zusammen und gibt diese zusammengesetzte
Zeichenkette aus. Dabei wird die Zeichenkette vollständig“, das heißt, dass ein Zeilenvorschub hin-
”
zugefügt wird.4 Dieses Verhalten, dass jeder Aufruf der print-Funktion eine vollständige Zeile liefert,
kann man dadurch ändern, dass man der print-Funktion den Parameter end=’ ’ mitgibt. Hier ist der
Parameter standardmäßig mit einem Zeilenvorschub ’\n’ belegt.
Das scheint keinen Unterschied zu machen, ob man in IDLE
>>> 3 + 4
oder
>>> print(3 + 4)
eingibt. Aber das ausdrückliche Ausgeben mit print“ ist intelligent, wenn mit Dezimalzahlen gerechnet
”
wird. Ein Beispiel dazu:
57
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
Das sollte man sich immer klar machen, wenn man viele Rechnungen mit Dezimalzahlen zu machen
hat.
Wenn man mit Brüchen rechnet, passiert das nicht. Bruchrechnen kommt weiter hinten in diesem
Kapitel, und darin wird dieses Beispiel nochmals mit Brüchen gerechnet.
58
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
Die Beschriftung sollte nicht nur gut lesbar sein, sondern auch etwas über den Inhalt aussagen. Stell
Dir vor, Du hast vor ein paar Monaten Deinen Keller aufgeräumt, alles was herumliegt in Kisten gepackt
und diese alle fein säuberlich beschriftet: Kruscht“ steht auf allen drauf!!! Und jetzt such mal in den
”
Kisten den USB-Stick mit den Bildern von der Geburtstagsfeier: er ist in einer der Kisten, aber wo?
Das im vorhergehenden Abschnitt beschriebene Verhalten von Python wird in der Informatik mit dem
Begriff dynamische Typisierung“ bezeichnet. Bei der dynamischen Typisierung wird einer Variablen
”
ein Typ zugeordnet, und damit verhält sich die Variable so wie es in der Typ-Beschreibung vorgegeben
ist. Das hat gewisse Vorteile, weil sich der Programmierer zum Beispiel keine Gedanken darüber ma-
chen muss, wie groß mögliche Werte für diese Variable sein können (so kann man also einer Variablen
textbeispiel sowohl den Wert Python als auch den Wert Donaudampschifffahrtsgesell-
schaftskapitän zuweisen). Python kümmert sich automatisch darum, dass ausreichend Speicher
zur Verfügung gestellt wird und dass, nachdem die Variable ihren Dienst getan hat, auch der Speicher
wieder freigegeben wird.7 Auf jeden Fall muss der Programmierer hier darauf achten, dass zum Bei-
spiel in der Variablen erg das Ergebnis 2.71828 steht. Das Ergebnis Always look on the bright
side of life ist vielleicht als mentale Aufmunterung erfreulicher, aber mit diesem Ergebnis kann
niemand, auch nicht Python, weiterrechnen.
Das Gegenteil der dynamischen Typisierung ist die statische Typisierung“. Hier muss der Program-
”
mierer von vorneherein festhalten, welche Art von Information in einer Variablen gespeichert werden
soll (eine Zahl, ein Text, eine Liste, eine Matrix), und meistens auch noch, wieviel Platz diese Information
(maximal) einnehmen kann.
Wir müssen noch festhalten, dass in der Informatik Ausdrücke benutzt werden, die einen Mathe-
matiker den Kopf schütteln lassen: es kann nämlich auf der rechten und der linken Seite des Zuwei-
sungsoperators, also des Gleichheitszeichens, die selbe Variable stehen. In Mathematik ist das folgende
sinnlos:
In Mathematik widersprechen sich die beiden Anweisungen: in der ersten steht, dass x den Wert 7
hat, die zweite Anweisung ist für keinen Wert von x richtig.
In der Programmierung ist das sehr sinnvoll. In der ersten Anweisung wird der Variablen x der Wert
7 zugewiesen, d.h. ab jetzt hat die Variable x den Wert 7. In der zweiten Anweisung steht (in einer Art
Pseudocode formuliert): nimm das, was in der Variablen x steht, zähle 2 dazu und weise das Ergebnis
der Variablen x zu; ab jetzt hat also x den Wert 9.
Einem Mathematiker oder Programmierer erscheint es selbstverständlich, aber es wird trotzdem hier
erwähnt: man kann einer Variablen beliebig oft einen Wert zuweisen.
7 Obdas ein Vorteil oder ein Nachteil ist, darüber können sich Programmierer prima streiten, vor allem zwischen Mötzingen und
Baisingen.
59
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
• Mit einer Anweisung kann auch verschiedenen Variablen verschiedene Werte zugewiesen werden.
Variable kennen wir schon aus der Mathematik. Allerdings sind die Mathematiker da sehr einfallslos
(jedenfalls in der Schule), denn Variable heißen hier grundsätzlich x. Aber das Prinzip der Variablen ist
hier das selbe: es wird ein Platzhalter geschaffen, der einen Namen bekommt, und diesem Platzhalter
kann man einen Wert zuweisen. Und nach einer Weile einen anderen Wert, so dass man mit der Zeit in
der Mathematik eine Wertetabelle bekommt.
In der (Schul-)Mathematik kennt man in der Analysis eine Variable, die dann fast immer x heißt, ganz
selten t, wenn man Funktionen in der Physik untersucht, bei der die Zeit variabel ist. In der Linearen
Algebra gibt es dann in der Schule schon mal 3 Variable, die dann x, y und z heißen, wenn man sie
nicht sogar einfach x1 , x2 und x3 nennt. In der Informatik benötigt man, um die Herstellungskosten
eines Produktes zu berechnen, viel mehr Informationen, also auch viel mehr Variable, die diese Infor-
mationen speichern, wie zum Beispiel stromkosten, abschreibungskosten, personalkosten,
materialkosten und noch viele mehr.
In der Programmierung ist man da viel flexibler (aber das hat man auch erst im Laufe der Jahre
gelernt). Variablennamen können länger als ein Zeichen sein, und das ist für die Lesbarkeit eines Pro-
gramms immer sehr sinnvoll. Denn ein Programm ist besser zu lesen und zu verstehen, wenn die Va-
riablennamen schon einen Hinweis auf die Werte geben, die sie später enthalten sollen. Natürlich kann
60
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
man in einem Programm für geometrische Berechnungen auch Variablen l und b nennen, aber auf den
ersten Blick verständlicher sind die Variablennamen laenge und breite.
3.3.2. Variablennamen
Variablennamen müssen mit einem Buchstaben oder mit einem Unterstrich beginnen, dann dürfen eine
beliebige Anzahl von Buchstaben, Zahlen oder Unterstrichen folgen.
A CHTUNG
Auch wenn die Entwickler eines weitverbreiteten Betriebssystems etwas ande-
res behaupten: in allen Bezeichnern, so auch in Variablennamen, haben Leer-
zeichen und Sonderzeichen nichts zu suchen.
Python lehnt zwar eine Variable länge nicht ab; besser ist die Variable laenge.
Denn Python arbeitet mit UTF-8, aber wer weiß, ob ein Entwickler, der mein
Programm weiterbearbeitet, auch schon diesen Standard auf seinem Rechner
hat.
Es ist sinnvoll und in produktiven Umgebungen oft auch gefordert, dass man sich beim Schreiben
von Programmen an gewisse Regeln hält. Firmen etwa legen in internen Richtlinien fest, dass z.B. Va-
riablennamen mit einem Kleinbuchstaben beginnen. Wenn der Variablenname ein zusammengesetztes
Wort ist, dann wird der Wortanfang des zweiten (und jedes folgenden Wortes) mit einem Großbuch-
staben geschrieben. Eine andere mögliche Vereinbarung ist, dass jeweilige weitere Wortanfänge durch
einem Unterstrich “ mit dem vorigen Teil des Variablennamens verbunden werden. Es trägt einerseits
”
zur Lesbarkeit von Programmcode bei, wenn hier Einheitlichkeit herrscht.8 Andererseits ist es auch für
die maschinelle Verarbeitung von Dateien, und Programme sind aus der Sicht des Dateisystems erst mal
nur Dateien, hilfreich, wenn etwa eine Python-Prozedur eine ganze Menge von Dateien bearbeiten soll
und Variablennamen nach dem selben Schema aufgebaut sind.
• zahl1
• zahl2
• grosseZahl
• ganzGrosseZahl
Auch hier muss ich auf etwas eingehen, was in unserem Kulturkreis lange Zeit eine Selbstverständlichkeit
war: der Satz Brandt hat in Moskau liebe Genossen“ hat eine andere Bedeutung als der Satz Brandt
” ”
hat in Moskau Liebe genossen“. Wenn man verschiedene Zeichen benutzt, bewirkt das eine unterschied-
liche Bedeutung. Erst mit dem Aufkommen von PC’s und dem eines (sehr schlichten) Betriebssystems
aus einem inzwischen sehr großen Softwarehaus von der Westküste der USA9 versuchte man, uns weis-
zumachen, dass die Datei [Link] und die Datei [Link] das selbe ist. Und leider schlagen sich
immer noch viele Software-Entwickler und PC-Benutzer mit diesem Übel herum.
In der Programmierung gilt einfach: Die Groß-/Kleinschreibung ist bei Variablen relevant!! liebe ist
etwas anderes als Liebe. Punkt. Aus. Ende der Diskussion.
8 siehe hierzu auch PEP 8 <[Link]
9 schon rausgekriegt, welches ich meine?
61
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
3.3.3. Wertzuweisung
Die Zuweisung eines Wertes an eine Variable ist leider inzwischen für viele Programmieranfänger ein
riesiges Problem. Also muss ich hier ein paar Sätze darüber schreiben. Ein Wert, egal ob ein Zahlenwert
wie 2,56“ oder ein Zeichenkettenwert wie And now for something completely different“ schwebt aus
” ”
der Sicht eines Programmierers nie frei in der Landschaft herum: er steht auf einem Speicherplatz. Wie
ich oben geschrieben habe: der Speicherplatz hat in modernen Programmiersprachen einen Namen.
Egal, ob ich den Wert lesen will, mit diesem Wert arbeiten möchte (ihn vergrößern, verändern, Teile
davon ersetzen usw.), ihn löschen will oder was mir sonst noch einfällt: ich muss als Programmierer
wissen, in welcher Variablen dieser Wert gespeichert ist. Wenn ich weiß, dass der Wert And now for
”
something completely different“ in der Variablen unsinn gespeichert ist, dann kann ich in einem Pro-
gramm zum Beispiel die Anweisungen
schreiben.
In fast allen Programmiersprachen, auch in Python, ist der Zuweisungsoperator das =“, das Gleich-
”
heitszeichen.10 Links des Gleichheitszeichens steht der Name der Variablen, der etwas zugewiesen wird,
rechts des Gleichheitszeichens steht der Wert, der zugewiesen wird. a = 17 bedeutet also, dass der Va-
riablen mit dem Namen a der Wert 17 zugewiesen wird.
W ICHTIG
Gewöhne Dir gleich an, vor und nach dem Gleichheitszeichen genau ein Leer-
zeichen zu lassen . . . und merke Dir das auch für alle anderen Texte, die Du
schreibst, nicht nur für Programme! a
10 Eine Ausnahme bilden die Wirth“-Sprachen, also Pascal, Modula und Oberon, die alle auf Niklaus Wirth zurückgehen. Hier
”
ist der Zuweisungsoperator ein :=“. Dafür ist der Vergleichsoperator auf Gleichheit hier ein einfaches =“.
” ”
Das hat den großen Nachteil, dass Zuweisungen immer zwei Tastendrücke bedeuten, und Zuweisungen sind häufiger als
Vergleiche! Den Mathematiker allerdings erfreut es, denn so lernt er es in den Anfangssemestern: a := 17 bedeutet: a hat jetzt
per Definition den Wert 17. Genau das ist aber eine Zuweisung.
62
KAPITEL 3. DIE . . . 3.3. EIN SPEICHERPLATZ MIT EINEM . . .
1. Weise einer Variablen mit dem Namen laenge den Wert 4 zu, weise einer anderen Variablen
mit dem Namen breite den Wert 12 zu, weise einer Variablen mit dem Namen flaeche den
Ausdruck laenge * breite zu. Was macht das Programm also? Welchen Namen würdest Du
diesem Programm geben?
2. Weise einer Variablen mit dem Namen laenge den Wert 4 zu, weise einer anderen Variablen
mit dem Namen breite den Wert 12 zu, weise einer Variablen mit dem Namen umfang den
Ausdruck 2 * laenge + 2 * breite zu. Was macht das Programm also? Welchen Namen
würdest Du diesem Programm geben?
3. Weise einer Variablen mit dem Namen laenge den Wert 4 zu, weise einer anderen Variablen
mit dem Namen breite den Wert 12 zu, weise einer dritten Variablen mit dem Namen hoehe
den Wert 7 zu,weise einer Variablen mit dem Namen volumen den Ausdruck 1 / 3 * laenge
* breite * hoehe zu. Was macht das Programm also? Welchen Namen würdest Du diesem
Programm geben?
3.3.5. Zuweisungsmuster
Aus einer netten Internetseite von (siehe [Lusth] ) übernehme ich hier die Idee der Zuweisungsmuster“.
”
Lusth unterscheidet
• das Transfer-Muster
• das Veränderungs-Muster
• das Wegschmeiß-Muster
Nehmen wir uns also die drei Muster der Reihe nach vor, aber in einer Kurzfassung. Wer interessiert ist,
sollte sich den Originaltext vornehmen!
(oder in Worten: der Variablen a wird der Wert 5, der Variablen b der Wert 7 zugewiesen.) Was
passiert aber, wenn ich schreibe: a = b? Welchen Wert hat nach dieser Zuweisung die Variable a,
welchen die Variable b?
Nun, einfach ist eine Antwort für b: an b ändert sich nichts, also muss der Wert von b immer noch
7 sein. Anders sieht es bei a aus: a wird b zugewiesen. Genau muss ich sagen: der Variablen a
wird der Wert zugewiesen, der in der Variablen b steht. Folglich steht in der Variablen a nach der
Zuweisung a = b auch der Wert 7.
2. Beim Veränderungs-Muster wird der Inhalt einer Variablen verändert.
11 in: Life of Brian
63
KAPITEL 3. DIE . . . 3.4. BRUCHRECHNEN
Was passiert? In der ersten Zeile wird der Variablen a der Wert 5 zugewiesen. In der zweiten Zeile
steht, in Worte gefasst: nimm den Wert der Variablen a, zähle zu diesem Wert 3 dazu und speichere
das Ergebnis wieder in der Variablen a. Damit hat a den Wert 8.
3. Das Wegschmeiß-Muster ist das, was viele Anfänger benutzen!
Das sieht sehr ähnlich aus wie das vorige Muster. Der Variablen a wird in der ersten Zeile der Wert
5 zugewiesen. In der folgenden Zeile wird der Wert von a um 3 erhöht . . . und weggeschmissen.
Genau gesagt: der erhöhte Wert wird nirgends gespeichert, ist also für alle Zeit verloren.
3.4. Bruchrechnen
Wie oben schon einmal gesagt: bei Python gilt batteries included“. Aber nicht alles ist im Kern von
”
Python. Manche Sprachelemente sind in Modulen ausgelagert. Obwohl Module erst später besprochen
werden, will ich hier schon einen Modul benutzen: den Modul fractions“. 12
”
Ein Modul wird in ein selbstgeschriebenes Programm (in der einfachsten Form) eingebunden durch
import fractions
Damit stehen in meinem Programm einige Möglichkeiten für das Bruchrechnen zur Verfügung. Einen
Bruch deklariere ich durch
bruch1 = [Link](3,4)
64
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
>>> i = 2
>>> summe2 = i + bruch1
>>> print(’Summe2:’, summe2)
(’Summe2:’, Fraction(11, 4))
>>> produkt2 = i * bruch1
>>> print(’Produkt2:’, produkt2)
(’Produkt2:’, Fraction(3, 2))
>>>
Hier kommt das Stück Code, das beim Rechnen mit Dezimalzahlen einen Fehler anzeigt. Mit Brüchen
ist alles in Ordnung.
2. ganze Zahlen sind eine Obermenge der natürlichen Zahlen. Sie enthalten zusätzlich noch negative
Zahlen: ..., -2, -1, 0, 1, 2, 3, ...
3. rationale Zahlen sind Brüche; rationale Zahlen können als endliche Dezimalzahlen oder als un-
endliche periodische Dezimalzahlen geschrieben werden
4. reelle Zahlen sind alle Dezimalzahlen, also auf jeden Fall alle rationale Zahlen und zusätzlich noch
alle nicht-periodischen unendlichen Dezimalzahlen
5. komplexe Zahlen bestehen aus einem Realteil und einem Imaginärteil und haben die Form z = 1
+ 3i
Da die Unendlichkeit für Computer und Programmiersprachen noch schwieriger zu behandeln ist als
für (menschliche) Philosophen und Mathematiker, werden alle Komma“-Zahlen mit einer endlichen
”
Zahl Stellen gespeichert und unter dem Typ float“ zusammengefasst.
”
In Python muss nicht angegeben werden, welche Art von Zahl in einer Variablen gespeichert wird.
Deshalb ist es manchmal sinnvoll, die Art der Zahl festzustellen. Das folgende kleine Python-Schnipselchen
65
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
benutzt Strukturen, die erst später erklärt werden. 13 Darum gibt es hier ansatzweise eine Erklärung,
was in dem Beispiel unten steht und was passiert. Die eckige Klammer enthält eine Menge von Zahlen,
als letztes Element allerdings ein Wort, das im Deutschen für eine Zahl steht. Das Schlüsselwort for
leitet eine Schleife ein, wodurch mit jedem Eintrag in der Liste etwas gemacht wird, es wird nämlich
überprüft, ob der jeweilige Eintrag eine Zahl der Klasse ganze Zahlen“ (int), der Klasse Fließkom-
” ”
mazahlen“ (float) oder der Klasse komplexe Zahlen“ (complex) ist. Das geschieht mit der Funktion
”
isinstance. Hier folgt das Beispiel dazu:
3.5.2. Operatoren
[Link]. Vergleichsoperatoren
Nachdem wir jetzt elementares Rechnen in IDLE ausprobiert haben, sollten auch noch weitere Operato-
ren genannt werden. Hier kommen zuerst einmal die üblichen Vergleichsoperatoren.
Besonders zu beachten in der obigen Tabelle sind die beiden Operatoren für die Gleichheit“. Das
”
sollte man auch in IDLE einmal ausprobieren, indem man zwei Variable definiert, die den selben Inhalt
haben:
Dann ergibt
>>> p1 == p2
13 Da es mehrere Strukturen sind, steht hier auch kein Verweis auf diese Strukturen.
66
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
True
>>> p1 is p2
False
das Ergebnis False liefert. True bzw. False sind hier selbstverständlich die beiden logischen Wahr-
heitswerte wahr“ bzw. falsch“.
” ”
A NMERKUNG
Die Wahrheitswerte True und False sind eigentlich ganzzahlige Werte; True
hat den Wert 1, False den Wert 0. Das sieht man bei folgenden Berechnun-
”
gen“:
Ebenso ist beachtenswert, dass Python hier beim Vergleich von Zahlen den Typ berücksichtigt.
>>> a = 3
>>> a == 6 / 2
True
>>> a == 6. / 2.
True
(man beachte die beiden Punkte! Hier werden zwei Dezimalzahlen geteilt!), erhält man den Wert True.
Der Vergleich
67
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
>>> a is 6 / 2
True
liefert auch den Wert True, wenn man allerdings Python fragt, ob
>>> a is 6. / 2.
False
Und Vorsicht: es ist auch ein Unterschied, ob man Zahlen und Texte miteinander vergleicht.
Die Zahl 3 ist kleiner als die Zahl 123; aber der Text 123“ kommt im Alphabet vor dem Text 3“, ist
” ”
also aus Sicht von Python kleiner.
Wenn man bereits andere Programmiersprachen kennengelernt hat, ist es interessant zu wissen, dass
man Vergleichsoperatoren verketten kann. Um in anderen Programmiersprachen zu überprüfen, ob eine
Zahl x zwischen 10 und 20 liegt, ist dort die Schreibweise
(wobei die Klammern normalerweise nicht nötig sind). In Python geht das einfacher durch
10 < x < 20
Man kann in Python bei Vergleichen vieles schreiben, aber man sollte nicht alles schreiben. Auch
y < x > z
68
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
ist für Python korrekte Syntax, aber hässlich (und wahrscheinlich in ein paar Wochen selbst für den
Schreiber unverständlich).
Weiter hinten bei Funktionen steht als Beispiel, wie man sich also eine kleine Funktion schreibt, die
ausgibt, ob eine Zahl zwischen zwei anderen Zahlen liegt.
[Link]. Verschiebeoperatoren
Speziell für Mathematiker und Informatiker interessant sind die Verschiebe-Operatoren. Verschiebe-
Operatoren verschieben das (unter Umständen gedachte) Dezimalkomma nach rechts oder links. Im
Dezimalsystem bewirkt das eine Multiplikation mit 10 (Komma wird um eine Stelle nach rechts verscho-
ben: aus 12,0 wird 120) oder eine Division durch 10 (Komma wird um eine Stelle nach rechts verschoben:
aus 12,0 wird 1,20)
So sieht das also im Dezimalsystem aus.
Da der Computer Zahlen im Dualsystem darstellt, bedeutet die oben beschriebene Operation (Zif-
fernfolge um eins nach links verschieben, hinten mit Null auffüllen) hier eine Multiplikation mit 2. Aus
diesem Grund gibt es in Python (wie in vielen anderen Programmiersprachen) spezielle Operatoren für
die Multiplikation mit 2 (bzw. mit Potenzen von 2) und die Division durch 2 (bzw. durch Potenzen von
2).
>>> (1 + 2j)
Das sollte man jetzt (sofern man gerade vor dem Rechner sitzt) einmal ausprobieren. Eine komplexe
Zahl besteht ja aus einem Realteil und einem Imaginärteil. Auch die kann man sich natürlich anzeigen
lassen:
69
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
Jetzt erinnert man sich daran, dass die imaginäre Einheit i definiert ist durch i*i = -1. Probieren
wir also einmal aus:
Die ersten beiden Versuche sind fehlgeschlagen, denn Python erwartet eine imaginäre Zahl in der
Form bj bzw. eine komplexe Zahl in der Form a +bj
Und jetzt ziehen wir endlich die Wurzel aus -1. Die Quadratwurzel (siehe weiter unten bei import
sqrt ) steckt im Modul math, der also zuerst importiert werden muss
Auch das funktioniert im ersten Versuch nicht. Die Quadratwurzel im Modul math kann nur die
Wurzel aus positiven reellen Zahlen berechnen. Für die Funktionen von komplexen Zahlen benötigt
man den Modul cmath.
Dann sollte es natürlich auch möglich sein, von einem in das andere Zahlsystem umzurechnen. Die
dafür zuständigen Funktionen heißen
1. hex für die Umrechnung einer Zahl im Dezimalsystem in eine hexadezimale Zahl. Das Ergebnis
ist eine Zeichenkette mit vorangestelltem 0x.
70
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
2. oct für die Umrechnung einer Zahl im Dezimalsystem in eine oktale Zahl. Das Ergebnis ist eine
Zeichenkette mit vorangestelltem 0o.
3. int für die Umrechnung einer Zeichenkette (also auch einer Hexadezimal- oder Oktalzahl) in eine
Zahl im Dezimalsystem.
3.5.5. Zufall
Selbstverständlich kann Python auch Zufallszahlen erzeugen. Dazu muss man einen Modul einbinden,
den Modul random. Ein Modul ist ein Stück Code, das jemand anderer geschrieben hat, und das funk-
tioniert. Das ist irgendwann einmal der Welt zur Verfügung gestellt worden. Das Einbinden geschieht
durch den Befehl import, hier also durch import random.
Jetzt wüssten wir natürlich gerne, was uns denn da alles bereitgestellt ist. Diese Information kann
man sich in zwei Darstellungsformen beschaffen:16
1. in der Kurzfassung, indem man sich nur ein Inhaltsverzeichnis anzeigen lässt
2. ausführlich, indem man sich die Hilfe zu dem Modul anzeigen lässt
16 Die Ausgabe wurde nach den ersten 6 Einträgen aus Platzgründen abgeschnitten.
71
KAPITEL 3. DIE . . . 3.5. RECHNEN UND VERGLEICHEN
NAME
random - Random variable generators.
FILE
/usr/lib/python2.7/[Link]
MODULE DOCS
[Link]
DESCRIPTION
integers
--------
uniform within range
Hier wurde der Befehl range benutzt. Der wird erst später bei den XrefId[?Schleifen?] eingeführt.
Wer nachblättern möchte: bitte schön. Für den, der das nicht will: range ist einfach ein Bereich.
72
KAPITEL 3. DIE . . . 3.6. SHORTCUT-OPERATOREN
3.6. Shortcut-Operatoren
Es gibt in Python (wie in vielen anderen Programmiersprachen) Abkürzungen für oft benutzte Rechen-
operationen, auf englisch shortcuts“. Für den Programmieranfänger sind diese abgekürzten Schreib-
”
weisen oft nicht so übersichtlich wie eine ausführliche Schreibweise. Aber wenn man sich das laut vor-
liest, was gemacht werden soll, dann ist das eine große Erleichterung, wenn man diese Abkürzungen
benutzt.
Immer wieder muss man zum Beispiel den Wert einer Variablen erhöhen. In einem konkreten Beispiel
heißt das, dass die Variable alter“ den Wert 17 hat, aber am nächsten Geburtstag muss die Variable auf
”
18 erhöht werden. Der Programmieranfänger schreibt das meistens so:
Klar, das löst das Problem. Auf den aktuellen Wert, den die Variable hat, wird 1 addiert und nach der
Addition wird der erhöhte Wert wieder in der Variablen alter“ gespeichert.
”
Die Abkürzung schreibt sich so:
Das kann man sich selbst so vorlesen, wie vor diesem Beispiel!
73
KAPITEL 3. DIE . . . 3.6. SHORTCUT-OPERATOREN
Shortcuts gibt es für alle elementaren arithmetischen Operationen. Das wird in der folgenden Tabelle
so aufgelistet.
74
4. Richtig programmieren
4.1. Entwicklungsumgebungen
4.1.1. Die Entwicklungsumgebung Eric
Nachdem wir also eine ganze Weile jetzt mit IDLE gearbeitet haben, stellen wir fest: um einen oder
vielleicht zwei oder drei Python-Befehle zu testen ist das nicht schlecht. Auch ein erfahrener Program-
mierer hat IDLE oft nebenher geöffnet, um einmal die Wirkungsweise eines Befehls auszuprobieren. Um
größere Programme zu schreiben, ist IDLE aber nicht sehr geeignet. Da gibt es wirklich komfortablere
Entwicklungsumgebungen.
Und wie heißt wohl der Nachfolger (oder die Erweiterung; oder Verbesserung) von IDLE? Na, blättern
wir zum Anfang des vorigen Kapitels, dort findet sich doch ein kleiner Tipp. Hast Du es rausgekriegt?
Die mächtigere Entwicklungsumgebung ist Eric“. Und sie sieht so aus:
”
In Eric“ können wir uns zum ersten Mal richtig daran machen, ein Programm zu schreiben. Das
”
richtig“ soll heißen, dass wir im Editor von Eric den Programmtext (auch Quelltext oder Quellcode
”
genannt) schreiben, in einer Datei speichern, und jetzt außerhalb von Eric auch diese Datei aufrufen
können.
75
KAPITEL 4. RICHTIG PROGRAMMIEREN 4.1. ENTWICKLUNGSUMGEBUNGEN
Unter Windows ist deswegen eine andere IDE sehr verbreitet, der PyScripter“. Der sieht so aus:
”
Abbildung 4.2. Die IDE PyScripter
Für kleinere Arbeiten existiert eine IDE unter Windows, die schlank und schnell ist und für Anfänger
ausreichend, die Geany“. Allgemein gilt hier: die IDE ist die beste, mit der ich am besten arbeiten kann.
”
Und die Geschmäcker sind verschieden.
76
KAPITEL 4. RICHTIG PROGRAMMIEREN 4.2. DAS ABSOLUTE MUSS: HALLO IHR ALLE
nem beliebigen Betriebssystem lauffähig sind, sollten wir uns hier bemühen, das Programm auch so zu
schreiben, dass das gewährleistet ist.2 Dazu gewöhnt man sich an, die unter Unix und MacOS übliche
sha-bang“-Zeile einzufügen, die dem Betriebssystem sagt, mit welcher Art von Programm (hier also:
”
mit dem Python-Interpreter) die Datei zu bearbeiten ist und wo sich der Interpreter befindet:
Der ist unter Unixen normalerweise im Verzeichnis /usr/bin . Aber leider nicht immer, deswegen ist
die bessere Methode die, dass man das Betriebssystem auffordert, den Interpreter selber zu suchen:
Hier wird das env-Kommando benutzt, das in der Umgebung (dem Environment) des Betriebssys-
tems nach dem Interpreter sucht.
Und diese Zeile wird von den DOS-ähnlichen Betriebssystemen (also Windows) großmütig ignoriert,
stört also in keinem Fall.
print(’hallo world’)
So einfach! Es ist keine Einbindung von Bibliotheken nötig (denke daran: batteries included!), keine
Tricks, die den Anfänger verwirren.
In der Zeile nach dem sha-bang steht etwas, das wie ein Kommentar aussieht. Das ist aber eine An-
weisung an den Interpreter, die ihm mitteilt, welche Kodierung das Programm benutzt. Hier ist die
Unicode-Kodierung utf-8“ eingestellt. Unter Windows 3 ist es oft sinnvoller, die Kodierung auf iso8859-
”
1 oder latin1 umzustellen.
2 Zu beachten hierbei ist allerdings, dass DOS (und damit Windows), Unix (und damit Linux) und MacOS verschiedene Zei-
chen benutzen, um den Zeilenvorschub zu kennzeichnen. Aber jedes der Betriebssysteme hat irgendein Hilfsmittel, um die
Zeilenende-Zeichen zu übersetzen.
3 wie immer zeitlich ein bißchen hinterher
77
KAPITEL 4. RICHTIG PROGRAMMIEREN 4.3. DIE ERSTEN EINFACHEN PROGRAMME
A NMERKUNG
Unter Python 3.x hat sich das geändert. Hier wird als Standard-Kodierung utf-8“
”
angenommen, das heißt, dass man diese Zeile nur noch schreiben muss, wenn
man auf einem System arbeitet, das noch nicht Unicode benutzt.a
print("Saftladen\n\n")
prApfelschorle = 0.70
prBananenmilch = 1.20
prOrangensaft = 0.80
Im zweiten Programm werden zwei Minuten-Zahlen von Benutzern eingegeben, und diese werden
in die üblichen Einheiten (x Stunden, y Minuten) umgerechnet:
78
Teil III.
79
5. Texte
And now for something completely different
(John Cleese 1 )
ist gleichwertig zu
Die Art der Anführungsstriche ist bedeutsam, wenn der Text selber Anführungsstriche bzw. Apostro-
phe enthält. Es funktioniert also
bzw.
Eine andere Möglichkeit, einfache Anführungsstriche in einem Text, der von doppelten Anführungsstrichen
eingeschlossen ist, zu benutzen (oder umgekehrt), ist das Maskieren“ von Anführungsstrichen:
”
81
KAPITEL 5. TEXTE 5.1. GRUNDLEGENDES ZU TEXTEN
Wenn wir das so in IDLE eingeben, ist es interessant zu sehen, wie das wieder ausgegeben wird. Es ist
wieder ein Unterschied ob man diesen Spruch ausgibt, indem man einfach den Variablennamen
>>> sinn
>>> print(sinn)
82
KAPITEL 5. TEXTE 5.1. GRUNDLEGENDES ZU TEXTEN
Python kann auch mit Texten rechnen.2 Was dabei herauskommt, wenn man Texte addiert oder einen
Text mit einer Zahl multipliziert, sieht man hier
So kann man also ganz schnell mal den Bildschirm von IDLE löschen:
>>> print(40*"\n")
83
KAPITEL 5. TEXTE 5.2. OPERATIONEN AUF TEXTEN
Selbstverständlich kann man somit auch jedes einzelne Element der Zeichenkette ansprechen:
Damit hat man schon das wichtigste Prinzip für die Bearbeitung von Texten verstanden! Man kann je-
den Text als Aneinanderreihung von Zeichen auffassen, und jedes einzelne Zeichen herausfiltern, indem
man den Namen der Zeichenkette gefolgt von der Hausnummer in eckigen Klammern angibt.
Dieses Prinzip wird jetzt aufgebohrt: man will ja oft nicht nur einen Buchstaben herausfiltern, son-
dern einen ganzen Bereich. Der technische Begriff dafür in Python lautet Slicing“. Der gewünschte
”
Teilbereich wird einfach in eckigen Klammern in der Form Anfangs-Element : End-Element an-
gegeben, wobei zu beachten ist, dass das Anfangs-Element mit ausgewählt wird, das Endelement das
erste Element ist, das nicht mehr ausgewählt wird.
Für Texte nicht so interessant ist, dass man hier auch noch einen dritten Parameter mitgeben kann.
Dieser gibt eine Schrittweite an, in der etwas aus einem Text herausgeschnitten werden soll
3 The times they are a-changing auf: The times they are a-changing
84
KAPITEL 5. TEXTE 5.2. OPERATIONEN AUF TEXTEN
Zur Erläuterung: das 3. Zeichen ist ein Leerzeichen!! (Nicht vergessen: man fängt bei 0 an zu zählen!!)
Am besten gefällt mir das folgende Problem: einen Text umdrehen (also von hinten nach vorne schrei-
ben), das, was wir als kleine Kinder gespielt haben. Wie heißt denn Du von hinten nach vorne?“ Mit
”
Hilfe von Python ist das ganz einfach:
Klar? Nimm den Text von Anfang bis Ende und gib ihn in der Schrittweite -1 aus.
Hier wird also wirklich an den Leerzeichen getrennt. Das Trennzeichen kommt dann in keiner der
Teillisten vor. Die einzelnen Teile kommen in eine Liste, und damit kann man die einzelnen Elemente
der Liste mit ihrer Hausnummer ansprechen (Beachte: das Zählen fängt bei 0 an!!). Wenn man als Index
eine negative Zahl benutzt, wird von hinten gezählt!
85
KAPITEL 5. TEXTE 5.2. OPERATIONEN AUF TEXTEN
Als Trennzeichen kann ein beliebiges Zeichen fungieren, sogar eine Zeichenkette ist möglich:
Aber Vorsicht: join ist eine Methode,4 die mit Texten arbeitet, nicht mit Listen. Deswegen steht ein
Text, in diesem Fall der Text, der aus einem einzigen Leerzeichen besteht, voran, gefolgt von einem
Punkt und dem Methodennamen. Das Argument der Methode ist in diesem Fall eine Liste.
Weitere Operationen auf Texten sind das Finden und das Ersetzen. Erinnere Dich an das oben gesagte:
Texte sind unveränderbar. Ein Ersetzen ändert den Inhalt der Variablen nicht. Aber das veränderte Stück
Text kann einer (anderen) Variablen zugewiesen werden. Das sieht so aus:
12
In Zeile 3 wird als Ergebnis des Suchens die Zahl 7 ausgegeben. Das heißt, dass das Programm den
gesuchten Text an der 7. Stelle des Namens gefunden hat. In Zeile 5 wird der Name ausgegeben mit der
Ersetzung, aber in Zeile 7 sieht man, dass der Wert der Variablen name noch unverändert ist.
Auch die Untersuchung, ob ein Textstück in einem Text enthalten ist, kommt relativ häufig vor. Das
geschieht über das Schlüsselwort in.
4 was das ist, kommt leider erst später, wenn ich Klassen einführe
86
KAPITEL 5. TEXTE 5.2. OPERATIONEN AUF TEXTEN
Weitere Methoden, mit denen man mit Texten arbeiten kann, werden hier unten als Befehl in eine
Shell eingegeben. Die Ausgabe spricht für sich selbst.
Wenn man mit Texten arbeitet, ist es oft nötig, überflüssige“ Zeichen zu entfernen, so etwa alle
”
möglichen Leerzeichen, auf englisch whitespaces“, am Anfang oder am Ende eines Textes. Zu diesen
”
Leerzeichen gehören
• das Leerzeichen
• der Tabulator
• der Zeilenvorschub
Dafür (und allgemeiner für die Entfernung beliebiger Zeichen) steht die Methode strip zur Verfügung.
Ohne einen Parameter werden genau die oben genannten Leerzeichen entfernt, aber man kann auch
einen oder mehrere Parameter in der Klammer angeben.
Ein Sonderfall für das Strippen ist das Entfernen eines Zeilenvorschubs am Ende einer Zeile. Das wird
später beim Lesen aus einer Datei relevant. Es wird erledigt durch [Link]()
Weiter oben in diesem Kapitel wurden die Steuerzeichen angesprochen. Während es in der Unix-Welt
fast keine Probleme mit Backslashes gibt, hat Microsoft leider dieses Zeichen als Pfad-Trenner miss-
87
KAPITEL 5. TEXTE 5.3. KODIERUNGEN
braucht.5 Das bringt Probleme mit sich, wenn man aus einem Programm heraus auf einen vollqualifi-
zierten Dateinamen zugreifen muss, also auf etwas in der Art
C:\Benutzer\Texte\Liebesbriefe
Da gibt es die Möglichkeit, den Backslash durch einen Doppelbackslash zu maskieren. Das macht ein
Programm nicht unbedingt lesbar. Die andere Möglichkeit ist, einen Text, der wie der obige Backslashes
enthält, als raw string“ zu codieren. Raw strings schalten die Interpretation des Backslashes als Steu-
”
erzeichen aus und interpretieren ihn als normales Zeichen. Das geschieht durch ein Voranstellen eines
r“. Beispiel:
”
verzeichnis = r’C:\Benutzer\Texte\Liebesbriefe’
Der erste Vergleich mit == stellt fest: ja, die beiden Variablen haben den selben Wert. Der zweite
Vergleich mit is stellt fest: das ist sogar das selbe Objekt, auf das jetzt nur zwei verschiedene Zeiger
weisen. Mittels der Funktion id sieht man jetzt, dass schlange und sprache tatsächlich die selbe
Adresse haben.
5.3. Kodierungen
Das ist unter Python3 (fast) kein Problem mehr! Zeichenketten in Python3 sind Unicode-Zeichenketten.
Das ganze Problem der Kodierung und Dekodierung taucht in Python3 nicht mehr auf.
Die Umsetzung von Zeichen in Maschinenzahlen (die berühmten 01000111 - Folgen) kann selbst-
verständlich auf verschiedene Art erfolgen. Dies ist eine Frage der Vereinbarung. Übliche Vereinbarun-
gen sind der ASCII 6 , der EBCDIC 7 , beide aus der Steinzeit der Datenverarbeitung. Das Problem dieser
alten Kodierungen ist, dass sie nur eine begrenzte Menge von Zeichen darstellen können. Aus diesem
Grund hat man sich Kodierungen überlegt, die mehr Zeichen aufnehmen können. Zuerst hat man beim
ASCII, der ursprünglich nur 128 Zeichen aufnehmen konnte, den Platz verdoppelt. Mit westeuropäisch-
nordamerikanischer Arroganz dachte man, damit alle Probleme gelöst zu haben: 26 Großbuchstaben, 26
5 ganz zu schweigen von dem mittleren Blödsinn, den uns manche weismachen wollen, dass in Dateinamen, Verzeichnisnamen
etc. Leerzeichen und Sonderzeichen auftreten dürfen
6 ASCII: American Standard Code for Information Interchange
7 Extended Binary Coded Decimals Interchange Code
88
KAPITEL 5. TEXTE 5.3. KODIERUNGEN
Kleinbuchstaben, ein paar Satzzeichen, die 10 Ziffern und dann für Französisch noch ein paar Vokale
mit Akzenten, für Deutsch noch ein paar Umlaute, da reichen doch 256 Zeichen.
Schnell hat man dann aber gemerkt, dass es so nicht geht. Kyrillisch, griechisch, türkisch, alle diese
Sprachen haben wieder eigene Zeichen. Also hat man für Sprachfamilien (wie zum Beispiel für die
nordeuropäischen Sprachen oder für die südosteuropäischen Sprachen) eigene Kodierungen erstellt,
die dann normiert wurden unter iso8859-x“. Dabei war x eine Zahl zwischen 1 und 15. Immerhin
”
konnte man dann in jeder Sprache die üblichen Zeichen darstellen, aber wenn man die Sprache (bzw.
die Sprachfamilie) verließ, musste man auch eine neue Kodierung auswählen.
Die Lösung heißt Unicode. Hier hat man Platz geschaffen, um auch Sprachen mit wesentlich mehr
Zeichen (wie zum Beispiel Chinesisch) aufzunehmen und dabei alles in eine Kodierung zu packen.
Unicode enthält weit über 100 000 Zeichen. Diese sind in Ebenen zusammengefasst, von denen jede 65
536 Zeichen enthält. Ebene 0 enthält die ASCII-Zeichen.
In Python3 können Unicode-Zeichen angegeben werden durch
1. \u gefolgt von einer vierstelligen Hexadezimalzahl. Damit werden Zeichen der elementaren Ebe-
nen (0 bis 256, in Hexadezimalschreibweise 00 bis FF) angegeben. Die ersten beiden Stellen der
Zahl geben die Ebene an, wobei 00 die ASCII-Ebene ist, die letzten beiden Stellen geben die Posi-
tion des Zeichens in der Ebene an.
2. \U gefolgt von einer achtstelligen Hexadezimalzahl. Damit werden Zeichen der höheren Ebenen
(größer als256) angegeben.
3. \N{Bezeichnung}, wenn die Bezeichnung des Zeichens bekannt ist.
89
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
Leider wird in diesem Skript der Schneemann nicht angezeigt. Aber auch dazu gibt es in unicodedata
eine Methode: [Link](’SNOWMAN’)
Nehmen wir an, wir wollen einen Gruß ausgeben, in den ein Name eingefügt werden soll.
90
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
Zuerst wird die Variable du deklariert, dann wird ein print-Befehl ausgegeben, der mit dem Text
Guten Tag,“ beginnt. Es folgt der Platzhalter für die Variable, versehen mit einem Formatierungsbefehl:
”
das erste %-Zeichen steht für die erste zu formatierende Variable; das darauffolgende s gibt an, dass
es sich bei der zu formatierenden Variablen um einen String, eine Zeichenkette, handelt. Es folgt ein
weiteres Stück Text, worauf sich das %-Zeichen, das Formatierungsanweisung von zu formatierenden
Variablen trennt, anschließt. Da wir in diesem Beispiel nur eine Variable haben, steht dort also nur die
Variable du.
A CHTUNG
In Python ab Version 3.x ist die Formatierung mit Hilfe der C-ähnlichen Syntax,
also der oben beschriebenen %-Anweisungen“ entweder verpönt oder verboten
”
(je nach Version). Hier funktioniert die Formatierung mittels der format-Methode
von Strings.
Das ganze wird interessant, wenn man auch Zahlen formatiert ausgeben will. Hier folgt eine Liste der
Format-Codes:
91
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
Seit Python 2.6 existiert eine weitere Möglichkeit, Ausgaben zu formatieren. Die Methode format bietet
ein paar zusätzliche Möglichkeiten, die die Formatierung komfortabler machen. Außerdem ist eine Feh-
lerquelle, die doppelte Bedeutung des Prozentzeichens innerhalb der Formatierungsanweisung, damit
hinfällig. Die allgemeine Syntax einer Formatierung mittels der format-Methode sieht so aus:
Das soll an einem Beispiel gezeigt werden. Hier sollen die Zahlen 1 bis 10, ihre Quadrate und ihre
Kuben (3. Potenzen) angezeigt werden. Zuerst läuft das Programm ohne Formatierung ab:
for i in range(10):
print(i, i**2, i**3)
Das sieht nicht gut aus, denn wir erwarten schon die Ausgabe in Spalten untereinander, wobei die
Zahlen wie gewohnt rechtsbündig geschrieben sein sollten.
Jetzt wird formatiert! Das kann auf zwei Arten realisiert werden:
2. indem man einen Format-Muster aufbaut und die Format-Methode von Zeichenketten mit dem
Format-Muster aufruft.
92
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
for i in range(10):
print([Link](i, i**2, i**3))
In dem Formatmuster steht für jeden Ausdruck, der ausgegeben werden soll, in einem Paar von ge-
schweiften Klammern eine Formatierungsanweisung. Nach dem Doppelpunkt steht dann in jeder ge-
schweiften Klammer in unserem Fall zuerst die Positionierungsanweisung >, die signalisiert, dass die
Ausgabe nach rechts geschoben wird, also rechtsbündig stehen soll. Danach steht die Feldbreite für die-
sen Teil der Ausgabe. Die 3 geschweiften Klammern geben also an, dass die erste Zahl auf 4 Stellen
Breite rechtsbündig geschrieben werden soll. Und die Ausgabe sieht doch gut aus!
Auch vor dem Doppelpunkt kann noch etwas stehen. Im einfachsten Fall kann dort eine Positionsan-
gabe der Werte, die ausgegeben werden sollen, gemacht werden. (Nicht vergessen: man fängt bei 0 an
zu zählen!!)
93
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
print()
for i in range(10):
print([Link](i, i**2, i**3))
Eine der oben erwähnten Verbesserungen der format-Methode ist, dass man Argumente an die For-
matierungsanweisung per Name übergeben kann. Das macht ein Programm besser lesbar (auch wenn
es für unser einfaches Beispiel noch nicht nötig ist), und deswegen steht der Quelltext hier ohne weitere
Erklärungen:
print()
for i in range(10):
print([Link](zahl=i, quadrat=i**2, kubus=i**3))
In der Spaltenformatierung kann der Bereich mit einem Füllzeichen ausgefüllt werden:
94
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
print()
for i in range(11):
print([Link](zahl=i, quadrat=i**2, kubus=i**3))
print()
for i in range(11):
print([Link](zahl=i, quadrat=i**2, kubus=i**3))
95
KAPITEL 5. TEXTE 5.4. FORMATIERUNG VON ZEICHENKETTEN
Für Zahlen können verschiedene Darstellungen gewählt werden. Hier folgen ein paar Beispiele, die
aber anhand der untenstehenden Tabelle leicht verstanden werden!
Zahlen werden mit dem Parameter d im Dezimalsystem, mit dem Parameter b im Dualsystem, mit
dem Parameter x im Hexadezimalsystem ausgegeben, wobei dann die abcdef“ in Kleinbuchstaben
”
geschrieben werden. Und hier kommt dann die ultimative Quizfrage: was bewirkt dann wohl der Para-
meter X?
In einer Tabelle folgen hier die wichtigsten Parameter für die format-Methode.
96
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
Reguläre Ausdrücke, auf englisch regular expressions“, deswegen auch manchmal einfach mit re“
” ”
abgekürzt, sind Ausdrücke, die Regeln gehorchen! Reguläre Ausdrücke sind eigentlich eine Program-
miersprache in der Programmiersprache, oder wie ein Kollege formuliert hat: die einzig wichtige Pro-
grammiersprache sind Reguläre Ausdrücke. Angenommen, Du suchst in einem Text nach einem Herrn
Maier oder Herrn Meier oder Herrn Majer . . . also genau das, was täglich passiert: wie schreibt sich der
Herr bloß? Wenn Du jetzt nur suchen könntest nach einem Herrn, dessen Nachname mit einem M“
”
anfängt, worauf einer der Buchstaben a“ oder e“ folgt, darauf einer der Buchstaben i“, y“ oder j“,
” ” ” ” ”
und dessen Nachname mit er“ endet! Das kannst Du! Denn oben hast Du gerade eine Regel festgelegt,
”
nach der der Ausdruck Nachname“ aufgebaut sein soll. Versuchen wir es also:
”
Hier soll nur ein kurzer Anriss des Themas gemacht werden. Wer sich weiter informieren will, dem
sei das Buch von [Friedl] empfohlen.
Reguläre Ausdrücke in Python beginnen sinnvollerweise mit einem r“, der Schreibweise für raw
” ”
strings“. Raw strings sind besondere Strings, die von Python so genommen werden, wie sie geschrieben
sind. In diesem Fall dient das dazu, dass Backslashes nicht als Steuerzeichen in Escape-Folgen interpre-
tiert werden. Der Raw string wird dann in Anführungsstriche eingeschlossen. Dieser raw string ist das
Muster, nach dem wir suchen, der reguläre Ausdruck.
Damit wir diesen Ausdruck aufbauen können, benötigen wir außer den Regeln, nach was wir suchen
die Vereinbarungen, was einzelne Zeichen in einem regulären Ausdruck für eine Bedeutung haben. Hier
folgen zuerst einmal die Regeln, die wir für unser Problem benötigen:
• ein beliebiges Zeichen des aktuellen Zeichensatzes bedeutet genau dieses Zeichen. M bedeutet M,
3 bedeutet 3.
• beliebige Zeichen in eckigen Klammern bedeuten, dass eines der Zeichen in der eckigen Klammer
genommen werden darf. [ae] bedeutet also, dass an dieser Stelle entweder ein a oder ein e stehen
darf.
Das reicht schon, um unser Problem zu lösen. Zuerst muss aber ein Modul eingebunden werden, das
sich mit regulären Ausdrücken befasst. Das geschieht mit der Anweisung import re“. Leider muss hier
”
vorgegriffen werden, denn Module werden erst in einem späteren Kapitel behandelt.
Um die Meiers“ noch weiter zu bemühen: es gibt in manchen Gegenden auch noch den Famili-
”
ennamen Mair“. Als Regel formuliert heißt das, dass das e“ fakultativ ist. Dazu benötigen wir einen
8 ” ”
Quantor , der genau 0 oder 1 bestimmtes Zeichen bzw. 0 oder 1 Zeichen aus einer Auswahl erlaubt. Das
erledigt das Fragezeichen, das dem bestimmten Zeichen folgt.
97
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
>>> Maier
Maier
Meier
Majer
Mair
Das Problem, das wir als erstes behandeln wollen, ist folgendes: aus einem beliebigen Text sollen alle
Wörter herausgefiltert werden, die mit einem h“ oder einem H“ anfangen. Die erste Lösung benutzt
” ”
fast die selben Python-Sprachmittel wie das vorige Beispiel:
98
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
In der runden Klammer des regulären Ausdrucks stehen zwei Teile, die durch den senkrechten Strich
voneinander getrennt sind. Das bedeutet, dass alle Zeichenketten gefunden werden sollen, die entweder
auf den regulären Teilausdruck vor dem senkrechten Strich passen oder auf den danach. Das \w ist
eine Kurzschreibweise für [A-Za-z0-9 ], findet also einen beliebigen Buchstaben, eine Ziffer oder einen
Unterstrich. Die Methode findall macht genau das, was ihr Name sagt.
Als nächstes sollen aus einem Text bestimmte Teile herausgefiltert werden. Suchen wir also in einem
Text nach unanständigen Sachen.
Der Text besteht aus 3 Zeilen, jede abgeschlossen durch einen Zeilenvorschub. Durch split wird der
Text in 3 Sätze aufgeteilt, die in einer Liste gespeichert werden. unanstaendeigeWoerter ist eine zu
Beginn leere Liste.
Mittels [Link]() wird nach einem regulären Ausdruck gesucht. Der reguläre Ausdruck setzt
sich so zusammen:
1. In eckigen Klammern steht eine Gruppe von Zeichen, aus denen genau eines ausgewählt werden
muss, in diesem Fall besteht die Liste aus dem Bindestrich und einem Leerzeichen. Die Variable
\s bezeichnet die Gruppe der white spaces“, also aller möglichen Leerzeichen.
”
2. Es folgt in runden Klammern die Zeichenkette Sex“.
”
3. Daran schließt sich wieder eine eckige Klammer an, in der die Menge aller Kleinbuchstaben steht.
Das bedeutet, dass von diesen Kleinbuchstaben wieder einer ausgewählt wird. Der Stern nach der
schließenden eckigen Klammer ist der Quantor, der besagt, dass null oder beliebig viele Klein-
buchstaben folgen dürfen.
4. Nach dem Stern steht die schließende runde Klammer. Dadurch wird das, was durch den in run-
den Klammern stehenden Teil des regulären Ausdrucks abgedeckt wird, als (Teil-)Gruppe eines
Fundes betrachtet.
5. Denn es soll ordentlich ausgegeben werden: das einleitende Leerzeichen oder der einleitende Bin-
destrich soll im Ergebnis nicht dargestellt werden, sondern nur das, was durch den in runden
99
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
Klammern abgedeckten Teil gefunden wird. Darum wird an die Liste der unanständigen Wörter
nur der Teil der 1. Gruppe angehängt.
OK. Das Programm hat gefunden, was es sollte. Syntaktisch ist es korrekt, aber naja, das ist nicht das,
was wir finden wollten.
Die ersten beiden Zeilen sollten jetzt verständlich sein; der Rest arbeitet mit einer Eingabe- und einer
Ausgabedatei. Das Original bleibt, wie es ist, die Ausgabedatei enthält nur Zeilen, in denen der reguläre
Ausdruck nicht gefunden wurde. Nach dem weiter hinten folgenden Kapitel über Dateien kannst Du
das Drumherum, das, was oben durch die 3 Pünktchen gekennzeichnet ist, leicht selbst schreiben.
Für eine einzelne Datei lohnt sich das Programm ja fast nicht, aber das Programm kann natürlich
weiter aufgebohrt werden, so dass es auf einen Schlag alle .gpx-Dateien eines Verzeichnisses bearbeitet.
Und dann lohnt es sich.
100
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
korrekteZahl = [Link](”’[0-9]+\.”’) akzeptiert eine Zahl, die aus den Ziffern 0 bis 9 besteht und
durch einen Dezimalpunkt abgeschlossen wird. Der Dezimalpunkt muss durch einen Backslash mas-
kiert werden.
korrekteZahl = [Link](”’([-+]?[0-9]+\.[0-9]{0,2})”’) akzeptiert eine Dezimalzahl, die aus den Zif-
fern 0 bis 9 besteht und nach dem Dezimalpunkt wenigstens 0 und höchstens zwei weitere Ziffern aus
der Menge 0 bis 9 enthält ([0-9]{0,2}). Aber das reicht noch nicht für eine gute Prüfung, denn es ist
noch erlaubt, dass ein Dezimalpunkt steht ohne Dezimalziffern danach.
Zusätzlich wird hier noch festgelegt, dass eine Zahl eine ganze Zeile ausfüllen muss. Das ˆ bedeutet,
dass re am Beginn der Zeile anfängt zu arbeiten, das $, dass re am Ende der Zeile aufhört.
korrekteZahl = [Link](r’’’(ˆ[-+]?[0-9]+(\.[0-9]{1,2})?$)’’’)
Der zweite Teil der Zahl, nämlich das, was hinter dem Dezimalpunkt stehen darf, ist hier durch runde
Klammern geblockt worden, so dass dieser Teil als ein Ausdruck aufgefasst wird ((\.[0-9]{0,2})?).
Für diesen Block wird dann wieder ein Quantor benutzt, nämlich das ?, das die Bedeutung hat: ent-
weder kein Mal oder ein Mal. In diesem Fall also darf eine mit einem Punkt beginnende und durch 2
Ziffern beendete Zeichenfolge kein Mal oder ein Mal auftreten.
—Kinderlied
Ein klassisches und deswegen ganz wichtiges Beispiel (hör Dich mal im Kindergarten Deines Wohn-
ortes um!) ist der philosophische Text
in dem alle (unterschiedlichen) Vokale und Diphtonge durch ein und denselben Vokal ersetzt werden
sollen. Dieses uralte Menschheitsproblem wird locker gelöst mit dem Programm
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 # importiere das Modul "Reguläre Ausdrücke"
5 import re
6
101
KAPITEL 5. TEXTE 5.5. REGULÄRE AUSDRÜCKE
Beachte dabei, dass die Diphtonge vor den Vokalen stehen müssen. Wenn die Diphtonge erst danach
stünden, würde etwa in ei“ zuerst das e“, dann das i“ ersetzt, wodurch aus dem ei“ ein oo“ würde
” ” ” ” ”
(wenn man als Ersetzungs-Vokal das o“ angibt).
”
Und das kommt dabei raus, wenn man als Ersetzungs-Vokal das o“ angibt:
”
Mit [Link] wird ein regulärer Ausdruck aufgebaut, der hier alternativ alle Vokale und Diphtonge
enthält. Und der Rest ist wieder klar. (Hoffentlich!)
Eine Suche per [Link] gibt ein Match-Object zurück. Jetzt kann es vorkommen, dass man genau
mit diesem Objekt weiter arbeiten muss. Was nun? Hier kommt die Hilfe zur Selbsthilfe: man weist das
Ergebnis des match-Aufrufs einer Variablen (z.B. der Variablen ergMatch) zu und ruft die Hilfe für
dieses Objekt mit help(ergMatch) auf! Dann sieht man unter anderem, dass das Objekt ergMatch ein
Attribut string hat. Das kann man ja mal ausdrucken!
Du sollst also in einem Text alle Wörter finden, die einen Doppelbuchstaben enthalten; Beispiele dafür
sind etwa See“, Meer“ und Leere“, die alle zwei aufeinanderfolgende e“ enthalten, oder Wall“,
” ” ” ” ”
Qualle“ und Welle“, die alle zwei aufeinanderfolgende l“ enthalten. Wie sieht die Regel aus?12
” ” ”
Die Regel sagt uns zuerst einmal, dass wir Wörter finden müssen. Wörter sind Zeichenketten, die von
Leerzeichen begrenzt werden. Auf sie passt also der reguläre Ausdruck \w*. Innerhalb dieses Wortes
soll also jetzt ein Buchstabe gefunden werden, der von dem selben Buchstaben gefolgt wird. Das ge-
schieht durch eine Gruppierung, auf die dann Bezug genommen wird. Eine Gruppierung wird durch
Einklammern erzeugt: (\w) ist eine Gruppe, die genau aus einem Element der Klasse \w besteht, also
aus einem Buchstaben, einer Ziffer oder einem Unterstrich.13 Diese Gruppe soll sich also jetzt wieder-
holen. Da es sich hier um die erste (und bis jetzt einzige) Gruppe handelt, beziehe ich mich auf diese
Gruppe durch den regulären Ausdruck \1“. Damit habe ich meine Regel beschrieben: gesucht sind
”
Wörter, die mit beliebig vielen Buchstaben beginnen, auf die ein Buchstabe folgt, der sofort noch einmal
folgt, gefolgt von beliebig vielen Buchstaben: \w*(\w)\1\w*“.
”
Der reguläre Ausdruck wird jetzt kompiliert, wodurch ein re-Objekt entsteht. Mit der Methode
finditer wird jetzt iterativ der Text durchsucht. Die eventuellen Ergebnisse stehen jetzt in dem Attri-
but group der einzelnen Objekte. Das Programm sieht so aus:
12 Ich gehe davon aus, dass der Text vorläufig in einer Variablen steht; die Bearbeitung von Text, der in einer Textdatei enthalten
ist, kann später jeder für sich programmieren, wenn der Zugriff auf Dateien bekannt ist.
13 Seien wir also mal kurzfristig großzügig (oder vielleicht schlampig?), und erlauben auch Ziffern in Wörtern, wodurch auch in
102
KAPITEL 5. TEXTE 5.6. AUFGABEN ZU TEXTEN (STRINGS)
text = ’’’In diesem Text sind mindestens zwee Wörter mit Doppelbuchstaben.
Findet er auch Meereswelle?’’’
wmdb = [Link](r"""\w*(\w)\1\w*""")
gefunden = [Link](text)
for i in gefunden:
print([Link](0))
>>> zwee
Doppelbuchstaben
Meereswelle
help(str)
den Hilfetext zu Strings anzeigen; probiere einige der dort angegebenen Methoden von Strings
aus. Notiere Dir Aktionen, die Dir interessant für Deien zukünftige Arbeit erscheinen, und spei-
chere die dazugehörigen Programmschnipsel in Python-Dateien.
Diese Sortierung gefällt Dir nicht? Mir auch nicht. Beschreibe Dein Missfallen, überlege Dir,
wie Du diese Wörter gerne sortiert hättest und schreibe ein Programm, das es besser macht.
4. Es stehen am Fahrrad-Rikscha-Startplatz:
a) 30 Fahrrad-Rikschas mit je 2 Sitzplätzen für Passagiere
b) 18 gut durchtrainierte Fahrer
c) 57 potentielle Fahrgäste
Ausgegeben werden soll etwa:
• Wir haben ... Rikschas, können also theoretisch ... Personen transportieren.
• Da im Moment nur ... Fahrer zur Verfügung stehen, können ... Fahrgäste mitfahren und ...
Fahrgäste müssen in ca. 1 Stunde wiederkommen, wenn sie dann noch fahren wollen.
5. Ein Programm soll aus dem Buchstaben x ein Herz malen, etwa so:
103
KAPITEL 5. TEXTE 5.6. AUFGABEN ZU TEXTEN (STRINGS)
Es ist sinnvoll, sich vorher ein Muster auf ein kariertes Papier zu malen!
Jetzt lass jeweils ein neues Programm die anderen Symbole der Spielkartenfarben Kreuz, Pik und
Karo malen. (Es muss nicht jedesmal mit einem x“ sein.)
”
104
6. Strukturierte Daten
6.1. Überblick
An strukturierten Daten unterscheidet man:
1. Listen
2. Dictionaries
3. Tupel
4. Mengen
Der Unterschied zu einfachen Daten ist einfach: bei einfachen Daten hat eine Variable einen Namen
und einen einzelnen Wert als Inhalt. Dieser Wert kann eine Zahl oder ein Text sein (und später werden
wir sehen: noch mehr). Bei strukturierten Daten ist der Inhalt einer Variablen eine Menge von Werten.
Eine Liste etwa kann eine Liste von Zahlen, eine Liste von Vornamen, eine Liste von Pizza-Angeboten
Deines Lieblingsitalieners usw. sein. Ein Dictionary kann ein einsprachiges Wörterbuch sein, ein zwei-
sprachiges Wörterbuch, ein Telefonbuch usw.
6.2. Listen
—Monty Python 1
W ICHTIG
Listen werden in eckige Klammern geschrieben, Listen-Elemente durch Kommata voneinander ge-
trennt. Wenn man ein einzelnes Element einer Liste bearbeiten (oder anzeigen oder ...) möchte, geschieht
das, indem man den Listennamen, gefolgt von der Hausnummer“ in eckigen Klammern, angibt.
”
W ICHTIG
Beachte dabei: Ein negativer Wert für den Index bedeutet, dass man von hinten
anfängt zu zählen.
105
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Die einfachste Art, eine Liste zu erzeugen, ist durch die Angabe der Elemente der Liste. Dabei weisen
wir gleich einer Variablen diese Liste zu:
Das kann man auch erledigen, indem man die Liste als ein Objekt der Klasse list“ erstellt und somit
”
den Konstruktor der Klasse aufruft.2
Bei Einführung von Schleifen lernst Du die Funktion range kennen. Diese Funktion liefert einen Bereich
von Zahlen. Dadurch ist sie auch gut geeignet, um Zahlenlisten herzustellen:
Beispiel 6.2.3 Eine Liste mit den ersten 20 natürlichen Zahlen erzeugen
zahlenListe3 = list(range(20))
A NMERKUNG
Hier ist ein Unterschied zwischen Python 2.x und Python 3.x! In Python 2.x hat
der Befehl range(20,50,3) bereits die oben angezeigte Liste erzeugt. In Python
3.x wird nur ein Generator für diese Liste erzeugt, die einzelnen Listenelemente
werden bei Bedarf erzeugt. Wenn man also in Python 3.x diese Liste erhalten
will, funktioniert das wie oben beschrieben durch list(range(20,50,3)).
2 DerSatz ist im Moment noch schwer zu verstehen; wenn Du weiter hinten in die Objektorientierte Programmierung eingestie-
gen bist, wird Dir der Sinn dieses Satzes hoffentlich klar.
106
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
A NMERKUNG
Wenn man jetzt auf die Idee kommt, dass man für eine Tabelle der x-Werte
(gewünscht ist dies für -5 <= x <= 5) einer Funktion in der Mathematik die-
se Tabelle durch x Werte = range(-5,6,0.1) erstellen kann, wird eine Fehler-
meldung bekommen: range erlaubt nur ganze Zahlen als Parameter. Aber das
gewünschte Ergebnis erhält man, wenn man das nächste Kapitel durchgelesen
hat.
A NMERKUNG
Klar jetzt, wie man die Wertetabelle aus dem vorigen Kapitel erzeugt? So:
defBereich = [x/10 for x in range(-50,51)]
oder so
107
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Listenelemente kann man einzeln ansprechen. Hier wird das erste Element der obigen Liste ausgege-
ben (denke daran: Python fängt bei 0 an zu zählen):
Diese Liste hat drei Elemente, zwei Texte und eine Zahl. Und auch hier kann man die Listenelemente
einzeln aufrufen:
108
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Immer wieder ist es aber auch wichtig, zu wissen, an welcher Stelle ein bestimmtes Element in einer
Liste steht. Dazu dient die Operation index gemacht.
Wenn weiter hinten bei der Zähl-Schleifen“ ein weiteres Element von Python zur Verfügung steht,
”
kann man den Zusammenhang zwischen der Länge einer Liste, ihren Elementen und den dazugehörigen
Hausnummern“ besser verstehen.
”
In Python gibt es eine eingebaute Funktion filter, die aus einer Liste mithilfe einer anderen Funktion,
die jedes Element einer Liste bearbeitet, eine gefilterte Liste erzeugt. Als Beispiel sollen hier einmal eine
Liste der Quadratzahlen kleiner als 650 erzeugt werden. Dazu wird eine Funktion geschrieben, die auf
Quadratzahl-sein“ überprüft.
”
109
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Eine andere Möglichkeit, etwas an eine Liste anzuhängen, ist, zwei Listen zu einer zu vereinigen. Das
sieht so aus:
Man kann Listen auch verlängern, indem man einen Shortcut-Operator benutzt. Aber Vorsicht: das
funktioniert nicht so, wie man es sich vielleicht naiv vorstellt.
Python fasst den Text Kölsch als eine Liste von Buchstaben auf, die einzeln angehängt werden. Richtig
wird es so:
110
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Wenn l eine Liste ist und man eine Methode von Listen auf l anwendet, wird l verändert, die Methode
gibt eine Erfolgs- oder Mißerfolgsmeldung zurück. Der Satz hört sich kompliziert an. Darum gibt es
gleich ein Beispiel:
2 >>> l = [1,2,3,4,5]
3 >>> print(l)
4 [1, 2, 3, 4, 5]
5 >>> [Link](6)
6 >>> print(l)
7 [1, 2, 3, 4, 5, 6]
8
9 >>> l2 = l
10 >>> print(l)
11 [1, 2, 3, 4, 5, 6]
12 >>> print(l2)
13 [1, 2, 3, 4, 5, 6]
14
15 >>> l2 = [Link](7)
16 >>> print(l)
17 [1, 2, 3, 4, 5, 6, 7]
18 >>> print(l2)
19 None
20
Hast Du gesehen, was passiert? Der Befehl in Zeile 13 hängt die Zahl 7 an die bestehende Liste l an.
Die Erfolgsmeldung dieser Operation wird der Variablen l2 zugewiesen.
Während man mit append nur ein einzelnes Element an eine Liste anhängen kann, ist es möglich, mit
extend mehr anzuhängen. Genau gesagt: an eine Liste kann mit extend alles Mögliche angehängt
werden, sofern es iterierbar ist. Dieser Satz ist aus 2 Gründen gemein:
1. erst im nächsten Kapitel, dem über Strukturierte Programmierung“, taucht der Begriff Iteration“
” ”
auf
2. da taucht ganz heimlich eine Art Rekursion auf: iterierbar bedeutet, dass etwas strukturiert ist,
und dass das etwas abzählbar ist, in der Form, dass man sagen kann, welches das erste Element
ist, und was dann das darauffolgende usw.
Also was? Na klar, eine Liste!!! Auf eine Liste trifft genau das zu, was im vorigen Satz steht. Also
kann ich eine Liste mit extend um eine Liste erweitern.
111
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Wenn ich hingegen mit append eine Liste anhänge, wird die Liste als ein Element genommen und
angehängt.
Es ist zwar nicht möglich, an eine Liste, die 4 Elemente enthält (also die Elemente 0 bis 3) ein weiteres
mit liste[4] = ’bla blub’ anzuhängen. Aber es gibt eine Möglichkeit, die so ähnlich aussieht:
Die Verlängerung in Zeile 6 ist gemeint: hier wird gesagt, dass die Listenelemente ab dem Element
mit der Hausnummer Länge der Liste“ die Namen Anne“ und Maria“ sein sollen.
” ” ”
112
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Für das Erweitern einer Liste um eine Liste gibt es allerdings noch eine Kurzschreibweise“; aber
”
vielleicht wärst Du da selber drauf gekommen, jetzt, nachdem Du Dich schon ein bißchen mit Python
beschäftigt hast:
Python verhält sich so, wie man es von einer vernünftigen Programmiersprache erwartet.
Hier geht es darum, an einer bestimmten Stelle ein Element einzufügen, also nicht mehr nur einfach an
das Ende der Liste etwas hinzuzufügen. Das Beispiel erklärt sich selbst (finde ich):
Entsprechend kann man auch etwas aus einer Liste entfernen, vorausgesetzt, man weiß, wo das gesuch-
te Element in der Liste steht.
Im vorigen Abschnitt habe ich die Art des Entfernens eines Elementes aus einer Liste als nicht so schön
bezeichnet. Das versteht man, wenn man weiter fortgeschritten ist und sich mit Objektorientierung be-
fasst hat. Schöner ist es, wenn man eine Methode der Klasse Listen“ benutzt. Die Methode pop()
”
holt ein einzelnes Element aus der Liste und löscht es darin. Wenn in der Klammer kein Parameter-
wert angegeben ist, also mit [Link]() wird automatisch das letzte Element entfernt. Will man
etwa das nullte Element (denke daran: Python fängt bei 0 an zu zählen) entfernen, geschieht das mit
[Link](0).
113
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Oben bei Zeichenketten als Feld haben wir schon den Begriff slicing“ kennengelernt. Das funktioniert
”
natürlich auch bei Listen.
Man kann eine Liste umkehren und anzeigen und dabei die Liste aber im Originalzustand lassen;
man kann aber auch die Liste umkehren und umgekehrt speichern.
Von Texten her bekannt ist schon das Slicing. Das funktioniert auch bei Listen. Hier wird mit 3 Para-
metern gearbeitet, um aus der Liste der ersten 10 natürlichen Zahlen die geraden Zahlen herauszufiltern.
Das ist wahrscheinlich eine der häufigsten Aufgaben, die bei einer Liste entstehen: sie soll sortiert wer-
den. Zum Glück hat Python für Listen die Methode sort. Sie sortiert die Elemente nach einer lexikali-
schen Ordnung:
114
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Dabei heißt lexikalisch“, dass im Sinne der ASCII-Ordnung sortiert wird, und da kommen alle Groß-
”
buchstaben AB..XYZ vor den Kleinbuchstaben ab..xyz. Beachte dabei: die Liste wird an Ort und Stelle
sortiert, das heißt, dass die Liste nach dem Sortieren nur noch in der sortierten Form existiert.
Da eine Liste beim Sortieren an Ort und Stelle verändert wird, ist es nicht ganz trivial zu überprüfen,
ob eine Liste sortiert ist. Durch die Funktion sorted wird eine neue Liste erzeugt, in die die Elemente
der gegebenen Liste in sortierter Reihenfolge eingefügt werden:
Die Funktion sorted erlaubt es also auch, eine sortierte Kopie einer gegebenen Liste zu erzeugen
und die ursprüngliche Liste unangetastet zu lassen:
Durch die Angabe des Sortierschlüssels key=[Link] werden alle Elemente aufgefasst, als wären
sie klein geschrieben. Merke: sie werden so aufgefasst, aber keineswegs geändert!!
Das kann man auch noch in anderer Form anwenden. Nach dem Schlüsselwort key kann nicht nur
ein Ausdruck stehen, sondern auch der Name einer Funktion, die etwas Sortierbares zurückgibt:
115
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
[Link](key=sortiere_nach_wortlaenge)
print(woerter)
def sortiere_nach_zweitem_Buchstaben(wort):
return wort[1]
[Link](key=sortiere_nach_zweitem_Buchstaben)
print(woerter)
[Link](key = nachnameExtrahieren)
Beispiel 6.2.38 Ergebnis der Sortierung einer Liste nach eigenartigen Kriterien
[’ist’, ’doof’, ’Martin’]
[’Martin’, ’doof’, ’ist’]
[’Carlo Carlowitsch’, ’Daniela Deppele’, ’Brigitte Maier’,
’Andreas Mueller-Morgenschoen’]
Ganz zu Anfang dieses Kapitels habe ich erwähnt, dass die Elemente einer Liste etwas beliebiges sein
können. Darauf warten natürlich die Mathematiker schon lange: eine Matrix ist einfach eine Liste von
Listen!
Allerdings ist die Darstellung bisher noch nicht so schön, damit müssen wir uns leider gedulden bis
zum Kapitel über die (Wer spickeln möchte: )Schleifen.
Jetzt kann man natürlich auf die Idee kommen zum Beispiel die 5x5-Nullmatrix über mit den oben
genannten Mitteln zu erstellen.
116
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Alles in Ordnung! Dann schreibe ich doch mal in die 3. Zeile 1. Spalte einen neuen Wert:
Das scheint auch gut funktioniert zu haben. Schaue ich mir also nochmal die gesamte Liste an:
Es scheint nur gut funktioniert zu haben! Beim Erzeugen der Matrix habe ich nämlich nur eine 5-
fache Kopie einer Nullzeile gemacht. Konkret: es existiert nur eine einzige Zeile, die 5 mal kopiert die
Matrix ergibt. Wenn ich jetzt also ein Element der Matrix ändere, ändere ich effektiv das angegebene
Spaltenelement jeder Zeile
Da hilft wieder nur, eine Kopie einer Nullzeile (vom ersten bis zum letzten Element) an eine leere
Liste anzuhängen:
117
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Es ist oft sehr hilfreich, dass die Elemente einer Liste durchnumeriert werden, manchmal ist es aber
auch lästig. Nehmen wir einmal an, dass wir in einer Liste Daten zu einer Person, sagen wir Vornamen,
Nachnamen und Schuhgröße speichern. So zum Beispiel:
Und nehmen wir weiter an, dass wir diese 3 Personen in einer weiteren Liste speichern wollen:
Dann kann man den Vornamen der zweiten Person (denke daran: man fängt bei 0 an zu zählen! Die
2. Person in der Liste hat den Index 1!!) natürlich so holen:
Beispiel 6.2.48 Ein Element einer Liste von Listen (eigentlich ein Matrix-Element)
allePersonen[1][0]
Das ist aber gegen alle Gebote der Schönheit, Nachvollziehbarkeit, Transparenz. Besser wird das da-
durch, dass man genau hinschaut und analysiert, wo was steht. Denn in der Liste jeder der Personen
steht der Vorname immer an erster Stelle, hat also den Index 0. Also baut man sich ein Tupel, das als
Inhalt die Begriffe Vorname, Nachname und Schuhgröße hat, und damit kann man jetzt viel eleganter
auf die Vornamen zugreifen. Hier kommt ein kleiner Programmausschnitt:
118
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
13 print(allePersonen[0][vorname])
14
Hier wird also in Zeile 11 ein Tupel mit den Zahlen 0,1,2 (Der Begriff range(3) tauchte bisher noch
nicht auf. Der kommt erst im Kapitel über Schleifen; er bedeutet: alle ganzen Zahlen von 0 (inclusive) bis
3 (exclusive) ) aufgebaut, das den Variablen Vorname, Nachname und Schuhgroesse zugeordnet wird.
Zeile 11 bedeutet aufgeschlüsselt, dass der Variablen vorname der Wert 0“, der Variablen nachname
”
der Wert 1“ und der Variablen schuhgroesse der Wert 2“ zugewiesen wird. Damit kann man auf
” ”
die Teile der Liste, die eine Person beschreibt, über diese Begriffe zugreifen. Das ist doch viel besser zu
lesen!
2 #!/usr/bin/python
3
4 zeilen = ["Martin, 1.91, 75", "Klaus, 1.72, 55", "Hannes, 1.82, 66"]
5
Das ist wirklich nur halbwegs gut, denn auch die Zahlen werden als Strings wiedergegeben.
119
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Die Verbesserung ist jetzt, dass ich eine Musterzeile erstelle, diese mit der Datenzeile zippe“ und erst
”
dann ausgebe:
Beispiel 6.2.52 Liste von Texten, diese sollen gesplittet werden, jetzt richtig
1
Und das wird jetzt besser. Zur Kontrolle gebe ich noch den Typ der Daten aus.
Das Problem soll gelöst werden, dass in mehreren Listen jeweils die ersten, zweiten ... Elemente zu-
sammengefügt werden sollen. Dazu benutzt man die Funktion zip.
Das ergibt
120
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
Und so wollten wir das doch . . . könnte man meinen!!! Aber Vorsicht! Hier wurde gar keine Kopie
angelegt, wie man bei den nächsten Anweisungen sieht:
also etwas, was man gar nicht wollte. Was ist passiert? Durch die Einführung der Variablen kopie
wurde dem Speicherbereich, der bisher den Namen meineListe hatte ein zweiter Name gegeben,
aber tatsächlich keine Kopie erstellt. Das wird als flache Kopie“ bezeichnet. Wenn ich wirklich eine
”
Kopie erstellen will, dann muss ich das per Slicing machen: alle Elemente der ursprünglichen Liste in
eine neue Liste kopieren. Aber das ist zum Glück nicht so schwer. Wir erinnern uns: liste1[1:3]
bedeutete alle Elemente der Liste vom ersten (inclusive) bis zum dritten (exclusive)“. Entsprechend
”
bedeutet liste1[2:] alle Elemente vom zweiten bis zum letzten“, liste1[:3] alle Elemente vom
” ”
Anfang bis zum dritten“, folglich liste1[:] alle Elemente vom ersten bis zum letzten“.
”
Beispiel 6.2.59 Kopie einer Liste: aber jetzt!!
>>> meineListe = [’Apfel’,’Birne’, ’Kohl’, ’Gurke’]
>>> kopie = meineListe[:]
Damit erstellt man ein neues Objekt, in das vom ersten bis zum letzten Element alles aus dem alten
Objekt reinkopiert wird. Das kann man jetzt sehen, wenn man wieder aus dem Kohl in der einen Liste
ein Sauerkraut macht.
121
KAPITEL 6. STRUKTURIERTE DATEN 6.2. LISTEN
erzeugen, die nur einen bestimmten Typ Daten enthalten dürfen, benutzen wir den Modul array.
Ein Array-Objekt erhält beim Erzeugen als ersten Parameter ein Kürzel für die Klasse von Objekten,
die es enthalten darf.
Beispiel 6.2.61 Ein Zahlen-Array ... und was damit nicht geht
>>> import array
>>> meinArray = [Link](’i’,[i for i in range(20)])
>>> print(meinArray)
array(’i’, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
Erzeugt wurde das Array mittels einer Comprehension. Und Zeichenketten oder Dezimalzahlen können
nicht angehängt werden, weil der erste Parameter beim Erzeugen, das ’i’, für integer steht, also für
Ganzzahlen.
122
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
class array([Link])
| array(typecode [, initializer]) -> array
|
| Return a new array whose items are restricted by typecode, and
| initialized from the optional initializer value, which must be a list,
| string or iterable over elements of the appropriate type.
|
| Arrays represent basic values and behave very much like lists, except
| the type of objects stored in them is constrained. The type is specified
| at object creation time by using a type code, which is a single character.
| The following type codes are defined:
|
| Type code C Type Minimum size in bytes
| ’b’ signed integer 1
| ’B’ unsigned integer 1
| ’u’ Unicode character 2 (see note)
| ’h’ signed integer 2
| ’H’ unsigned integer 2
| ’i’ signed integer 2
| ’I’ unsigned integer 2
| ’l’ signed integer 4
| ’L’ unsigned integer 4
| ’q’ signed integer 8 (see note)
| ’Q’ unsigned integer 8 (see note)
| ’f’ floating point 4
| ’d’ floating point 8
6.3. Dictionaries
A cat’s meow and a cow’s moo
You know I could recite them all
(Bob Dylan3 )
Dictionaries gibt es in vielen Programmiersprachen (nur heißen sie dort anders, nämlich hashes“
”
oder assoziative Arrays“). Das charakteristische für Dictionaries ist, dass hier die Elemente nicht mehr
”
durchnumeriert werden wie in Listen, sondern Werte unter einem Schlüssel abgelegt werden. Jeder
Dictionary-Eintrag ist also ein Paar von Informationen, wobei die erste Information Schlüssel“ (engl.
”
key), die zweite Information Wert“ (engl. value) genannt wird. Dictionaries werden in geschweifte
”
Klammern geschrieben. Im ersten Dictionary soll tatsächlich ein Wörterbuch abgelegt werden.
Der Schlüssel eines der Paare ist also hier das englische Wort für ein bestimmtes Tier, der Wert ist
die deutsche Übersetzung dafür. Ein Element eines Dictionary wird also nicht mehr durch eine Haus-
3 Quinn the eskimo auf: Basement Tapes
123
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
nummer gefunden, sondern über den Schlüsselbegriff. Wichtig ist es manchmal, alle Schlüssel oder alle
Werte eines Dictionary zu bekommen, manchmal auch beides:
Eine kleine Anwendung von Dictionaries folgt, wenn Schleifen behandelt worden sind.
Der Versuch des Zugriffs auf ein Dictionary über einen Schlüssel, der nicht existiert, führt aber zu
einem sehr unerwünschten Abbruch des Programms:
Die Fehlermeldung ist hier deutlich: Zugriff mit einem Schlüssel, der nicht existiert.
Dictionaries haben aber die Zugriffsmethode get, der man einen Defaultwert mitgeben kann:
124
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
Eine weitere Methode, setdefault, leistet noch mehr. Während get nur einen Default-Wert ausgibt,
kann man mit setdefault einen Neueintrag in das Dictionary machen:
Man sieht: beim ersten Aufruf von get wird nur das Fehlen angezeigt, beim zweiten Aufruf ist der
Wert vorhanden. Man muss auch keine Sorge haben, dass ein bereits bestehender Wert überschrieben
wird:
Das letzte get wäre sogar überflüssig gewesen: setdefault setzt einen neuen Wert, falls der Eintrag
im Dictionary noch nicht existiert; falls er existiert, wird der Wert zurückgegeben.
Mit Hilfe dieser Methode ist es elegant möglich, etwa die Buchstaben häufigkeit eines Textes zu
zählen. Man legt ein leeres Dictionary an und addiert 1 dazu bei jedem Auftreten eines Buchstaben.
Falls in dem Dictionary noch kein Eintrag zu einem Buchstaben existiert, wird mit get“ der Wert 0
”
eingetragen. Für die Ausgabe dieses und der beiden nächsten Schnipsel benötigen wir eine Schleife, die
aber erst später im Text bei Einführung von Schleifen kommt.
Das ist nicht schlecht, aber bei der Häufigkeit von Buchstaben interessiert Groß-/Kleinschreibung
nicht. Besser wäre also:
125
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
Und jetzt folgt die Komfort-Version, nämlich die alphabetische Ausgabe der Häufigkeiten. Die Schlüssel
werden dazu in einer Liste gespeichert, sortiert, und über diese sortierte Liste wird geschleift:
(In der ersten Zeile der Ausgabe steht das Leerzeichen, das 8 mal auftaucht!!!)
Der Modul collections enthält verschiedene Erweiterungen zu strukturierten Daten, so zum Bei-
spiel das defaultdict. Das ist ein Dictonary, dem ein Defaultwert beim Anlegen zugeteilt werden
kann. Das soll an einem einfachen Beispiel gezeigt werden, bei dem die Vornamen einer Person der
126
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
Schlüssel, der Wohnort dieser Person der Wert sein soll. Leider wohnen die meisten betreffenden Perso-
nen nicht in München, Gilching oder Starnberg, sondern in Oberpfaffenhofen; aber diesen langen Orts-
namen will niemand öfter als nötig schreiben. Also schreibe ich eine Funktion oph zurueckgeben, die
diesen Namen zurückgibt.
Apfelsaft 0.8
Birnensaft 1.85
Kirschsaft 2.14
Mangosaft 2.25
Orangensaft 1.3
127
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
6.3.3. Was ist denn das irgendwas“, das in einer Liste oder einem Dictionary
”
stehen kann?
Alles!
import math
print(wildeListe[1](wildeListe[0]))
print(wildeListe[2].sin(wildeListe[3]/2))
print(wildesDic[’wurzel’](wildesDic[’zahl1’]))
print(wildesDic[’mm’].sin(wildesDic[’pi’]/2))
Da steht also in der wilden Liste an Position 0 eine Ganzzahl, an Position 1 aus dem Modul math die
Wurzel-Funktion sqrt, an Position 2 der gesamte Modul math und an Position 3 die aus dem Modul
math importierte Konstante pi. Das wilde Dictionary ist sehr ähnlich aufgebaut, nur im Verhältnis zur
Liste wurden der gesamte Modul und die Wurzel vertauscht.
Ein anderes nettes Beispiel ist die Caesar-Verschlüsselung. Dazu baue ich ein Dictionary mittels zip
auf, dessen Schlüssel die Kleinbuchstaben und dessen Werte die Zahlen 0 bis 25 sind. Dieses Dictionary
drehe ich um, so dass Schlüssel zu Werten und Werte zu Schlüsseln werden, um den Geheimbuchstaben
herauszufinden.
128
KAPITEL 6. STRUKTURIERTE DATEN 6.3. DICTIONARIES
2 #!/usr/bin/python
3
4 import string
5
8 caesar = dict(zip(string.ascii_lowercase,range(len(string.ascii_lowercase))))
9 caesar_invers = dict(zip([Link](),[Link]()))
10 verschiebung = 3
11
12 geheimtext = ’’
13 for b in klartext:
14 if [Link]() in caesar:
15 index = caesar[[Link]()] + verschiebung
16 geheimtext += caesar_invers[index % len(string.ascii_lowercase)]
17 else:
18 geheimtext += b
19
20 print()
21 print(’Klartext: \t\t%s\nGeheimtext: %s’ % (klartext, geheimtext))
22
Das kann auch dadurch geschehen, dass man für die Berechnung des Wertes eine Funktion aufruft:
Beispiel 6.3.18 Erzeugung eines Dictionaries Zahl / Quadratzahl über eine Funktion
def qZahlBerechnen(x):
return x*x
129
KAPITEL 6. STRUKTURIERTE DATEN 6.4. TUPEL
r = range(1, 21)
qDic = dict(zip(r, map(qZahlBerechnen, r)))
for z in qDic:
print(z, qDic[z])
6.4. Tupel
Tupel? Warum gibt es die? Denn Tupel sind eigentlich nur Listen, allerdings sind sie unveränderlich.
Tupel werden in runde Klammern geschrieben. Und außerdem haben Tupel keine Methoden. Aber das
sind schon die relevanten Unterschiede. Meistens wird man sich für Listen entscheiden, wenn man
Objekte in einer Struktur ablegen will.
Eine ganz schöne Anwendung, und für Programmierer, die mit anderen Programmiersprachen groß
geworden sind, ungewöhnlich, ist das Vertauschen von 2 Objekten. Der Pseudocode für eine solche
Vertauschung sieht so aus (und so muss das auch in fast allen Programmiersprachen codiert werden):
temporaeresDing = ding1
ding1 = ding2
ding2 = temporaeresDing
In Python sieht der Programm-Code so aus, wie sich das der naive Programmierer vorstellt. Dabei wird
benutzt, dass Python bei Zuweisungen die runden Klammern von Tupeln nicht benötigt:
Eine interessante Anwendung für Tupel sind die benannten Tupel. Mit ihnen kann man komplexe Da-
tenstrukturen abbilden. Okay, das macht man in einer objektorientierten Sprache wie Python über Klas-
sen, aber manchmal ist ein benanntes Tupel auch ganz effektiv, etwa wenn man weiß, dass das ähnliche
Objekte ähnliche Eigenschaften haben, aber das Verhalten dieser Objekte uninteressant ist.
Als Beispiel dienen hier Fahrzeuge. Die namedtuple gehören nicht zum Python-Kern, müssen also
importiert werden. Ein benanntes Tupel wird angelegt, indem man ihm einen Namen und eine Liste von
Eigenschaften gibt. Dann legt man ein Exemplar an, indem man den Eigenschaften einen Wert zuweist.
Jetzt kann man die Eigenschaften über ihren Namen abrufen:
130
KAPITEL 6. STRUKTURIERTE DATEN 6.5. ZUSAMMENFASSUNG
6.5. Zusammenfassung
Hier folgen noch mal die wichtigsten Eigenschaften der strukturierten Daten in einer Tabelle.
1. Python speichert eine Menge nicht unbedingt in der Reihenfolge, in der sie eingegeben wurde,
genau wie bei Dictionaries.
2. Die Mathematiker wissen es: in einer Menge ist ein bestimmtes Element höchstens einmal enthal-
ten. Deswegen ist in der gespeicherten Menge nur eine 3“.
”
131
KAPITEL 6. STRUKTURIERTE DATEN 6.6. MENGEN (SETS)
die Menge aller Elemente, die in der einen und auch in der anderen Menge enthalten sind. Der Operator
für die Vereinigung ist das | (der senkrechte Strich), denn die Vereinigungsmenge ist die Menge aller
Elemente, die in der einen oder in der anderen Menge enthalten sind (oder in beiden; der Mathematiker
nennt das ein nicht ausschließliches ODER“ im Gegensatz zum ausschließlichen ODER“, das in der
” ”
deutschen Sprache mit ENTWEDER ... ODER“ gesprochen wird).
”
Auch die Differnzmenge kann erzeugt werden, selbstverständlich durch das Minuszeichen. Aber Vor-
sicht: die Differenz ist nicht symmetrisch:
In der Differenz menge1 - menge2“ sind alle Elemente von Menge1, die nicht in Menge2 sind. Die
”
symmetrische Differenz, also die Elemente von Menge1, die nicht in Menge2 sind zusammen mit den
Elementen von Menge2, die nicht in Menge1 sind, wird durch den Operator ˆ gebildet:
Teilmenge ist eine Menge, die einen Teil der Elemente der ursprünglichen Menge enthält. Der Opera-
tor ist das <=-Zeichen, für die echte Teilmenge das <-Zeichen
132
KAPITEL 6. STRUKTURIERTE DATEN 6.6. MENGEN (SETS)
Entsprechend werden für die Obermenge die Operatoren > bzw. >= verwendet.
Für Mathematiker ist das klar, aber auch für Andere ist das verständlich.
Hier kommen noch einige Mengenoperationen, realisiert durch Methoden der Klasse set:
133
KAPITEL 6. STRUKTURIERTE DATEN 6.7. AUFGABEN ZU LISTEN, DICTIONARIES . . .
Frau
Mathilde Weber
Primus-Truber-Straße 123
72072 Tübingen
Deutschland
Das bietet sich an als ein Dictionary von Dictionaries. Überlege Dir sinnvolle Ausgaben dieser
Datenstruktur.
134
KAPITEL 6. STRUKTURIERTE DATEN 6.8. VERÄNDERBARKEIT VON DATEN
Wie gesagt: es ist nicht so einfach, aus Sandra einen Sandro zu machen; die Fehlermeldung sagt uns
genau das, dass nämlich ein Element eines str-Objects keine Zuweisung erlaubt.
Bei einer Liste sieht das ganz anders aus.
Das klappt.
Die Unveränderlichkeit von Zeichenketten hat auch eine Bedeutung für die Speicherung von Varia-
blen. Schauen wir, was passiert, wenn man zwei verschiedenen Variablen die selbe Zeichenkette zu-
weist. Nach diesen zwei Zuweisungen schauen wir uns mit Hilfe von id an, an welchem Speicherplatz
der Text gespeichert ist.
Beide Variable haben die selbe Adresse!! Um Speicherplatz zu sparen, wird der Text nur einmal ge-
speichert, da Python ja weiß, dass dieser unveränderlich ist. Also werden die Variable a und die Va-
riable b ihren (gemeinsamen) Wert immer an der richtigen Stelle finden. Der Speicherplatz, an dem die
Information Martin“ steht, hat zuerst den Namen a bekommen, später noch ein Pseudonym, einen
”
Alias-Namen, nämlich b.
Wenn man die selbe Aktion mit zwei Listen durchführt, geschieht etwas völlig anderes.
135
KAPITEL 6. STRUKTURIERTE DATEN 6.8. VERÄNDERBARKEIT VON DATEN
Tatsächlich: zwei verschiedene Adressen. Das muss so sein, denn jede Liste könnte verändert werden,
also müssen die beiden Variablen auf verschiedene Speicherplätze zugreifen.
Weiter unten bei den Funktionen werden wir sehen, dass das unter Umständen Probleme bereiten
kann.
136
Teil IV.
Strukturen
137
7. Programmstrukturen
Don’t think twice, it’s alright
(Bob Dylan1 )
7.1.1. Kontrollfluß
Darum haben wir uns bis jetzt noch nicht gekümmert! Bis jetzt wurde ein einzelner Befehl ausgeführt,
bestenfalls ein paar Befehle hintereinander; und es gab keine Möglichkeit, von dieser Reihenfolge abzu-
weichen. Der Fluß des Programms war linear und von uns eindeutig vorgegeben.
Das soll sich jetzt ändern, wir werden in den Kontrollfluß eingreifen. Das geht grundsätzlich auf zwei
Arten: durch Wiederholungsanweisungen und durch das Treffen von Entscheidungen. Also stürzen wir
uns rein ins Vergnügen! Aber damit alles seine Ordnung hat, wird das Thema des linearen Programms
gleich als erstes aufgegriffen.
139
KAPITEL 7. PROGRAMMSTRUKTUREN 7.2. EINS NACH DEM ANDEREN: DIE . . .
• Ausgabe:
– Gesamtkosten für die Fahrt
– Kosten je Person
11. Quader:
• Eingabe:
– Länge des Quaders
140
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
7.3.1. Wahrheit
Hier muss ein kleines Kapitel eingeschoben werden, das sich mit Wahrheit befasst. Dazu gilt es, ein paar
Fragen zu stellen und zu beantworten.
1. Welche Wahrheitswerte gibt es?
2. Welche Arten von Termen gibt es?
3. Bei welchen dieser Terme kann man sinnvoll die Frage nach einem Wahrheitswert dieses Terms
stellen?
4. Wenn ich mehrere solcher Terme habe:
a) Wie kann ich sie sinnvoll verknüpfen?
b) Wie sieht es bei einer solchen Verknüfpung mit der Wahrheit aus?
Die erste Frage ist einfach zu beantworten: eine Aussage kann wahr oder falsch sein. Da Program-
miersprachen sich an der englischen Sprache orientieren: sie kann true“ oder false“ sein. In Python
” ”
entspricht das den Werten True und False. Diese Werte werden Boole’sche Werte“ genannt, eine
”
Variable, die nur diese Werte annehmen kann, heißt entsprechend Boole’sche Variable“ 2
”
Hier folgen verschiedene Arten von Termen: Ziffern, Zahlen, Buchstaben, Texte, Gleichungen, Bedin-
gungen ...
Zur dritten Frage: jetzt sollten wir die Arten von Termen auf einen möglichen Wahrheitswert unter-
suchen. Python hilft uns dabei, denn Python enthält die Funktion bool, die den Wahrheitswert eines
Termes zurückgibt.
1. Kann eine Ziffer wahr oder falsch sein?
>> bool(9)
True
>>> bool(5)
True
>>> bool(1)
True
>>> bool(0)
False
>>> bool(-1)
True
>>> bool(-9)
True
141
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
2. Kann ein Buchstabe oder ein Text wahr oder falsch sein?
>>> bool(’a’)
True
>>> bool(’Z’)
True
>>> bool(’ä’)
True
>>> bool(’Python’)
True
>>> bool(’Python ist klasse!’)
True
>>> bool(’ ’)
True
>>> bool(’’)
False
Fazit: Jeder Text der Länge 1 bis unendlich ist wahr. Nur der Text, der aus nichts besteht, ist falsch.
Bedingungen sind die interessanteste Art von Termen. Eine Bedingung ist normalerweise der Ver-
gleich von zwei Dingen, meistens einem konstanten Wert und dem Wert einer Variablen. Beispiele (in
natürlicher Sprache), wobei die Variablen, mit denen verglichen werden soll, explizit in Klammern an-
gesprochen werden, sind:
Hier ist klar: alle diese Bedingungen können, als Frage gestellt, mit Ja“ oder mit Nein“ beantwortet
” ”
werden, in der Sprache der Informatik mit True“ oder mit False“.
” ”
Zwischen den Werten, die in einer Bedingung miteinander verglichen werden, steht ein Vergleichs-
operator. Zu den elementaren“ Vergleichsoperatoren siehe weiter vorne im Buch.
”
Die ersten drei dieser Beispiele sollen jetzt in Python formuliert werden.
Beispiel 7.3.1
>>> n = 18
>>> n > 17
True
>>> n = 5
False
>>> n > 17
142
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Beispiel 7.3.2
>>> nachname = ’Schimmels’
>>> nachname == ’Meier’
False
>>> nachname = ’Meier’
>>> nachname == ’Meier’
True
Beachte hierbei: der Vergleich auf Gleichheit geschieht durch zwei aufeinanderfolgende Gleich-
heitszeichen. Siehe oben bei Vergleichsoperatoren
3. Ist Pfeffer“ ein Gewürz?
”
Beispiel 7.3.3
>>> listeGewuerze = [’Salz’,’Curry’,’Paprika’]
>>> ’Pfeffer’ in listeGewuerze
False
>>> listeGewuerze = [’Salz’,’Curry’,’Pfeffer’,’Paprika’]
>>> ’Pfeffer’ in listeGewuerze
True
Eine Bedingung kann immer den Wahrheitswert wahr“ oder den Wahrheitswert falsch“ haben.
” ”
Dieses Beispiel zeigt eigentlich nur, dass True“ das Gegenteil von False“ ist (und umgekehrt). Aber
” ”
Vorsicht: das sind Variable, und deswegen dürfen diese Wörter keineswegs in Anführungsstrichen ge-
schrieben werden.
Oft sind Bedingungen zusammengesetzt, und aus diesem Grunde muss man sich Gedanken darüber
machen, was eine Aussage wie WAHR und FALSCH“ oder wie WAHR oder FALSCH“ bedeutet. Das
” ”
macht man meistens in sogenannten Wahrheitstafeln“. Zum Glück ist das, was man in der Programmie-
”
rung benötigt, überschaubar. Jetzt soll die Frage der Verknüpfung von Bool’schen Termen angegangen
werden. Es gibt 3 elementare Verknüpfungen:
143
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
1. mit und“
”
2. mit oder“
”
3. mit nicht“
”
print(’UND-Verknüpfung’)
print(’\n\nODER-Verknüpfung’)
print(’\n\nNICHT-Verknüpfung’)
Die Ausgabe des Programms sind die 3 Verknüpfungstafeln, und das sieht so aus:
144
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Die logischen Verknüpfungen und“ und oder“ werden im Kurz-Verfahren ausgewertet. Was das be-
” ”
deutet, sieht man mit einem Zwischenblick auf die obigen Verknüpfungstafeln. Eine und“-Verknüpfung
”
hat den Wert falsch“, wenn die erste Aussage falsch ist; eine oder“-Verknüpfung hat den Wert wahr“,
” ” ”
wenn die erste Aussage wahr ist. In diesen beiden Fällen wird die Auswertung abgebrochen, weil das
Ergebnis jetzt schon fest steht.
Aber Vorsicht: wenn man zwei Aussagen mit oder“ verknüpft und die erste Aussage ist falsch, wird
”
die zweite Aussage zurückgegeben. Das liefert unter Umständen nicht das gewünschte Ergebnis:
Ich glaube, Du willst jetzt mal testen, ob Du das alles verstanden hast. Also kommt hier eine Entschei-
dungstabelle, in die Du in die letzte Spalte den korrekten Wahrheitswert eintragen sollst.
Wenn Du merkst, dass das noch nicht so ganz locker klappt, denk Dir noch mehr solche Übungen
aus!
Als erstes kommt hier ein Beispiel, das ich letzthin bei einem Programmieranfänger gesehen habe. Die
Aufgabe war, ein Programm zu schreiben, das bei einer Schulnote von 5 oder 6 den Text nicht versetzt“
”
ausgibt. In Pseudocode (s. Glossar) geschrieben:
145
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Die Umgangssprache hat uns hier auflaufen lassen! Schauen wir den Term hinter dem if an:
1. Der Inhalt der Variablen note soll auf Gleichheit mittels == verglichen werden
2. mit dem, was hinter dem Vergleichsoperator steht,
3. also mit dem Term 5 or 6
4. Jetzt schauen wir weiter oben noch mal nach:
a) 5 ist eine Zahl ungleich 0, hat also den Wahrheitswert True
b) 6 ist eine Zahl ungleich 0, hat also den Wahrheitswert True
c) True mit or verknüpft mit True ist True
d) Ergebnis: Wenn die Note von 0 verschieden ist, ist der Vergleich immer True, also wird außer
bei der Note 0 immer NICHT VERSETZT ausgegeben.
Korrekt muss das Programm so aussehen:
3 Alternative bedeutet tatsächlich nur eine Auswahl aus zwei Möglichkeiten; in der Umgangssprache (aber leider oft auch in der
Fachsprache) wird Alternative oft als Auswahl unter mehreren Möglichkeiten“ beschrieben.
”
146
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Die Bedingung fragt hier das Geschlecht der Person ab. Die Auswahl wird getroffen zwischen der
Anrede Herr“ und Frau“.
” ”
Üblicherweise wird eine Bedingung formuliert, indem
• zwei Werte miteinander verglichen werden
• der Wert einer Variablen mit einem Wert verglichen wird
• der Wert einer Variablen mit dem Wert einer anderen verglichen wird
Es gibt dabei verschiedene Möglichkeiten, einen Vergleich zu formulieren:
• es wird auf Gleichheit untersucht
• es wird auf Ungleichheit untersucht
• es wird auf Größe mit Hilfe von größer“, kleiner“ größer oder gleich“, kleiner oder gleich“
” ” ” ”
untersucht
Die Zeile, die mit dem Schlüsselwort WENN“ beginnt, heißt Kopf der Alternative, das was gemacht
”
werden soll, wenn die Bedingung erfüllt wird (oder auch nicht), ist der Körper. Die Begriffe Kopf und
Körper werden auch später bei der Iteration und bei Unterprogrammen wieder auftauchen.
Eine solche Schreibweise, bei der Wörter der Alltagssprache benutzt werden, aber eine Syntax, die
sich an die Logik wird Pseudocode“ (s. Glossar) genannt. Und zum Verhältnis von Pseudocode einer
”
Programmiersprache anlehnt, zu Programmen in der Programmiersprache Python sagt Lutz 4 : Because
”
Python’s syntax resembles executable pseudocode, it yields programs that are easy to understand, change,
and use long after they have been written“ Es gibt also wenig Gründe, in einem Skript über Python
Pseudocode zu verwenden, denn Python-Code sieht wie Pseudocode aus. Wenn ich es mache, dann
meistens nur, um etwas auf deutsch (und nicht auf englisch) zu schreiben.
Der Code in Python sieht dann so aus:
147
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Und auch hier sollte man noch mal einen genießerischen Blick auf die Ähnlichkeit des Pseudocodes
und des Python-Codes werfen!
Auch wenn es einigen Lesern überflüssig erscheint, muss hier kurz auf den Begriff Bedingung“ ein-
”
gegangen werden. Eine Bedingung ist eine Aussageform, die entweder den Wert WAHR“ oder den
”
Wert FALSCH“ annehmen kann. In Python wird durch True der Wert WAHR“, durch False der
” ”
Wert FALSCH“ angegeben. Beachte hierbei die Groß-/Kleinschreibung der Wahrheitswerte in Python!
”
148
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
>>> if z1 == z3:
... print(z1, ’ = ’, z3)
... print(z1 == z3)
... else:
... print(z1, ’ != ’, z3)
... print(z1 != z3)
...
3 = 3
True
>>> t1 = ’gut’
>>> t2 = ’schoen’
>>> if t1 == t2:
... print(t1, ’ = ’, t2)
... print(t1 == t2)
... else:
... print(t1, ’ != ’, t2)
... print(t1 != t2)
...
gut != schoen
False
Das ist vermutlich leicht nachzuvollziehen. Also kommen hier entsprechende Vergleiche auf größer“
”
und kleiner“
”
149
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Nachdem man das gelesen und verstanden hat, sollte man auf der Python-Shell oder in Idle ähnliche
Dinge probieren.
Nur eine kleine Selbstverständlichkeit sollte hier am Rande erwähnt werden: das Gegenteil von größer“
”
ist NICHT kleiner“!! Das Gegenteil von größer“ ist nicht größer“, oder anders gesagt: das Gegenteil
” ” ”
von größer“ ist kleiner oder gleich“!!
” ”
[Link]. Kurzschlüsse
Kurzschlüsse in der Elektrik sind schlecht. In der Programmierung sind Kurzschlüsse oft erlaubt, manch-
mal sinnvoll, sie machen Programmcode kürzer ... aber sie machen Programmcode nicht immer verständlicher.
Auch bei der Alternative gibt es die Möglichkeit des Kurzschlusses. Dazu kommt hier zuerst das
ausführliche Beispiel. Inzwischen verstehst Du dieses Beispiel ohne weitere Kommentare:
Verständlich, ordentlich, aber ein bißchen viel Schreibarbeit. Kurzschlüsse machen es kürzer!
150
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Die beiden Texte ’Schuhe, sondern kleine Boote’ und ’Boote!!’ haben jeweils den boole’schen Wert
True. Der Ausdruck in der Klammer ist also dann wahr, wenn sg größer als 45 ist, und dann wird der
erste Text (der vor dem or) ausgegeben, falls sg nicht größer als 45 ist, ist der Ausdruck in der Klammer
falsch und der zweite Text (der nach dem or) wird ausgegeben.
Da sich Programmiersprachen an die englische Sprache anlehnen, sind die Schlüsselwörter der engli-
schen Sprache entnommen. Das obige umgangssprachliche Beispiel ließe sich in Python so formulieren.
Beachte dabei, dass als Abschluss der Bedingung so wie im umgangssprachlichen Text ein Doppelpunkt
steht.
Wie sieht es aber aus, wenn ich mehrere Möglichkeiten zur Auswahl habe? Guten Morgen, guten Tag,
guten Abend, gute Nacht!
Wenn man eine solche Mehrfachentscheidung treffen muss, gibt es eine Faustregel: arbeite entweder
von groß“ nach klein“ oder von klein“ nach groß“, aber vermische nie die Vorgehensweisen. Das
” ” ” ”
führt zu logischen Fehlern, die man im Moment des Schreibens (vor allem, wenn man noch nicht so viel
Erfahrung mit dem Schreiben solcher Anweisungen hat) aber gar nicht merkt. Als Gegenbeispiel mische
ich das obige Beispiel nur ein wenig durch:
151
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Gehen wir das also mal in Handarbeit durch, für den Fall, dass die Variable stunde den Wert 19 hat:
1. beim ersten if stellt Python fest, dass der Wert größer als 10 ist, also wird nicht in das erste print
(den Guten Morgen“) verzweigt, es wird also nichts ausgegeben
”
2. beim zweiten if stellt Python fest, dass der Wert größer als 18 ist, also wird nicht in das zweite
print (den Guten Tag“) verzweigt, es wird also nichts ausgegeben
”
3. beim dritten if stellt Python fest, dass der Wert kleiner als 24 ist, also wird in das dritte print (die
Gute Nacht“) verzweigt, es wird also Gute Nacht“ ausgegeben, obwohl hier der Guten Abend“
” ” ”
angebracht wäre
Außer bei der Programmierung gibt das vor allen Dingen bei unseren Kindern richtig Ärger: Es
”
ist doch noch gar nicht so spät, und ich will doch noch den Tatort im Fernsehen schauen und
überhaupt ist das unfair!“
4. das vierte if wird nämlich gar nicht mehr überprüft, weil das Programm ja schon eine korrekte
Entscheidung getroffen hat. Dann hört es auf zu vergleichen!
Du siehst: durch ein Nichteinhalten einer natürlichen Reihenfolge wird hier eine Bedingung bejaht, die
eigentlich verneint werden müsste.
else:
if
geben ja eine logische Ebene an. Der else-Zweig hat als erstes Konstrukt eine weitere Bedingung. Die
auf dieses else folgende Anweisung ist, zusammen mit der oben drüber stehenden Anweisung und
den darunter stehenden im Prinzip eine Auswahl unter mehreren Möglichkeiten. Deswegen gibt es in
Python ein zusammengezogenes else if, nämlich das elif. Das obige Beispiel sieht besser so aus:
5 Wie oft habe ich das wohl schon geschrieben? Aber es ist wirklich so: wenn etwas nicht schön aussieht, dann ist es auch
meistens nicht schön programmiert, und dann kann man das Programm (auf jeden Fall in Python!) ästhetischer schreiben,
damit besser lesbar. Und das ist auch meistens die bessere Lösung.
152
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Es ist im Übrigen guter Stil, und man ist damit auch auf der sicheren Seite, wenn man eine solche
Mehrfachauswahl mit einem else abschließt, damit auch alle vorher nicht ausdrücklich aufgelisteten
Fälle behandelt werden. Meistens ist der Programmierer nämlich froh, wenn das Programm mit den Da-
ten, die er sich vorstellt, korrekt funktioniert, und er denkt nicht an alle unmöglichen“ Möglichkeiten,
”
auf die ein Anwender kommt.
ist gleichwertig zu
Die erste der beiden oben stehenden Varianten besticht durch ihre Kürze. Die zweite Variante ist dafür
einfacher auf eine fehlerhafte Eingabe zu erweitern:
153
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Um das mit Hilfe eines Dictionary zu erledigen, muss man die get“-Methode von strukturierten
”
Daten benutzen.
Die get-Methode erlaubt als zweiten Parameter einen Default-Wert, der hier auf falsche Eingabe“
”
gesetzt wurde.
154
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
6. Die Signum-Funktion gibt den Wert 1 zurück, wenn die eingegebene Zahl positiv ist, den Wert 0,
wenn die eingegebene Zahl 0 ist und den Wert -1, wenn die eingegebene Zahl negativ ist. Schreibe
ein Programm!
7. Eine einfache Prüfziffer für 7-bit-Zeichen (den Standard-ASCII) könnte so funktionieren: wenn die
Anzahl der Einsen ungerade ist, setze das 8. bit auf 1, wenn die Anzahl der Einsen gerade ist, auf
0.
8. Mitternachtsformel (oder für Nordlichter: die allgemeine Lösungsformel für quadratische Glei-
chungen) ist zu programmieren. Eingabe der Koeffizienten a, b, c der quadratischen Gleichung
ax2 + bx + c = 0 in das Programm mit Hilfe von variable = input . . .“. Ausgabe von Diskriminan-
”
te, Anzahl der Lösungen und gegebenenfalls der Lösungen.
9. Das Programm zur Berechnung des Body-Mass-Index aus Kapitel 4 soll dahingehend verbessert
werden, dass es eine Bewertung ausgibt. Dabei gilt, dass Frauen mit einem BMI kleiner oder gleich
19 und Männer mit einem BMI kleiner oder gleich 20 untergewichtig sind, Frauen mit einem BMI
größer oder gleich 24 und Männer mit einem BMI größer oder gleich 25 übergewichtig sind.
10. Ein Programm soll ausgeben, ob ein Jahr ein Schaltjahr ist. Beachte dabei, dass die durch 100
teilbaren Jahre keine Schaltjahre sind, außer wenn sie durch 400 teilbar sind.
11. Für die Berechnung des Wochentages hat C.F. Gauss folgende Formel aufgestellt (dabei ist die
seltsame eckige Klammer, bei der der obere Haken fehlt, das Symbol für die Gauss’sche Klam-
merfunktion, die bedeutet: größte ganze Zahl
kleiner oder gleich als das, was in dieser Klammer
steht): w = (d + b2, 6 · m − 0, 2c + y + y4 + 4c − 2c) mod 7
• y: Die beiden letzten Stellen der Jahreszahl (für 2007 wäre diese 07 also 7)
• c: Die beiden ersten Stellen der Jahreszahl (für 2007 wäre diese 20)
Fast selbstverständlich ist, dass verknüpfte logische Operationen von links nach rechts abgearbeitet
werden. Wenn ein Ausdruck wie x > 3 or x < -2 auftaucht, wird zuerst geprüft ob x > 3 ist.
Jetzt aber!!! Jetzt verhält sich Python ausgesprochen vernünftig. Weiter oben bei der XrefId[?oder-
Verknüpfung?] haben wir gesehen, dass eine ver-oderte“ Verknüpfung wahr ist, wenn ein Teil wahr
”
ist. Wenn x also den Wert 7 hat, dann ist der erste Teil, nämlich x > 3 wahr. Also ist es völlig egal, ob der
zweite Teil, nämlich x < -2 wahr oder falsch ist, der gesamte Ausdruck ist wahr.
Dann braucht man also nicht weiterzulesen, was mit dem zweiten Teil passiert, denn der gesamte
Ausdruck wird wahr sein. Also liest Python nicht weiter.
Das ist gut so, denn das Programm spart dadurch Zeit. Es läuft schneller! Na gut, bei einem einzel-
nen Ausdruck ist die Zeitersprarnis nicht der Rede wert, aber wenn ein Programm Hunderte solcher
Vergleiche enthält, dann merkt man das vielleicht doch. Viel wichtiger ist, dass man damit aber eine
elegante Methode hat, mögliche Fehler abzufangen.
Nehmen wir uns als Anwendung dafür die Mitternachtsformel vor. Dazu benötigt man die (Quadrat-
)Wurzel-Funktion, auf englisch die square root, als Funktion sqrt. Die steckt im Modul für Mathematik,
der import werden muss mit import math. Das Programm könnte in seiner schlichtesten Form so aus-
sehen:
155
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
156
KAPITEL 7. PROGRAMMSTRUKTUREN 7.3. WENN . . . DANN: DIE ALTERNATIVE
Da wollte jemand also den absoluten Härtetest machen, und ausprobieren, ob unser tolles Programm
auch die Nullstelle einer linearen Funktion berechnen kann, also hat er einfach für den Koeffizienten
a eine 0 eingegeben. Wenn man sich den Quelltext weiter oben nochmal anschaut (oder noch besser:
wenn man weiß, dass in der Mitternachtsformel durch 2 * a geteilt werden muss), dann ist klar, dass
ein Fehler auftaucht.
Es ist aber relativ einfach, diesen Fehler abzufangen, d.h. zu verhindern, dass eine fehlerhafte Eingabe
wie oben das Programm abbrechen lässt, wenn man das oben gesagte über vernüpfte Logik-Operatoren
nochmals liest und sich dann erinnert, dass ein mit und“ verknüpfter logischer Ausdruck nur dann
”
wahr ist, wenn beide Teile wahr sind. Also fragt man einfach an den kritischen Stellen nicht nur den Wert
der Diskriminante ab, sondern zuerst den Wert des Parameters a. Ich nenne das Vorgehen Aufpasser“,
”
weil diese zusätzliche Abfrage aufpasst, dass die kritische Variable einen sinnvollen Wert enthält. Also
sieht das so aus:
157
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
In den beiden Zeile mit den Bedingungen, also den Zeilen die mit if bzw. mit elif beginnen, steht
jetzt also vorne die Abfrage, ob a ungleich 0 ist. Und jetzt passiert nichts schlimmes mehr:
Klar? Wenn a den Wert 0 hat, ist der erste Teil des mit und“ verknüpften Ausdrucks falsch, damit ist
”
der ganze Ausdruck falsch, und damit wird dieser Ausdruck nicht weiter untersucht. Also wird auch
gar nicht versucht, durch 0 zu dividieren, und alles ist in bester Ordnung. Zugegeben, das ist noch nicht
die absolut anwenderfreundliche Kommunikation des Programms, aber schon ein ganzes Stück besser,
als mit einer Fehlermeldung abzubrechen.
7.4. Schleifen
God knows when
But you’re doin’ it again
(Bob Dylan 6 )
Lies noch einmal nach, was weiter oben über gute Programme geschrieben wurde. Ein Programm der
Art (das ist kein Python-Programm, sondern nur Pseudocode!)
geht also gar nicht. Mehrmals die selbe Anweisung, nur mit verschiedenen Werten: das muss zu
vereinfachen sein.
Jetzt geht es also um die Wiederholung von einer Anweisung oder einer ganzen Gruppe von An-
weisungen. Endlich lohnt sich das Programmieren! Ganz allgemein kann man das Problem auch so
umschreiben: hier ist eine Menge von Dingen; mach für jedes von ihnen das selbe (oder etwas sehr
ähnliches).
Eine solche Wiederholung, Schleife genannt, kann prinzipiell auf zwei Arten realisiert werden:
• Man gibt die Anzahl der Wiederholungen an. In diesem Fall spricht man von einer Zählschleife.
In der Programmierung nennt man das eine for-Schleife“.
”
• Man weiß nicht genau, wie oft etwas wiederholt werden soll, sondern man kann nur angeben,
wann man mit der Wiederholung aufhören soll. Anders gesagt, man kennt die Abbruchbedingung
für die Wiederholung. Dies wird als while-Schleife“ programmiert.
”
Diese beiden Arten sollen noch an einem Beispiel verdeutlicht werden: es sollen alle Zahlen von 1 bis
100 ausgedruckt werden. Hier folgt die Realisierung, so wie wir sie mit den bisherigen Mitteln erreichen
könnten:
6 Subterranean Homesick Blues auf: Bringing It All Back Home
158
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
(Im Titel des Beispiels steht umgangssprachlich, weil für den Mathematiker die ersten 100 natürlichen
die Zahlen von 0 bis 99 sind.) Das funktioniert. Aber das ist nicht schön, kein Mensch wollte so etwas
schreiben, es ist fehleranfällig, kurz: so nicht! Die erste oben beschriebene Art, dieses Problem zu lösen,
nämlich in einer Zählschleife, sieht in Pseudocode so aus:
Nicht schlecht: statt 100 Zeilen Programmcode sind das 2 Zeilen Pseudocode. Und wir werden sehen:
daraus werden nach der Übersetzung einiger Schlüsselwörter auch genau 2 Zeilen Python-Code.
Die zweite oben beschriebene Art, dieses Problem zu lösen, nämlich in einer Schleife mit Abbruchbe-
dingung, sieht in Pseudocode so aus:
Auch nicht schlecht: die 100 Zeilen Programmcode von oben sind zu 4 Zeilen Pseudocode geschrumpft.
Das wird auch wieder zu 4 Zeilen Python-Code, und zwar genauso einfach wie bei der Zählschleife.
Allerdings kann man hier schon eine Faustregel festhalten, wenn man die Faust aufmacht und die
Finger nachzählt: 4 ist doppelt so viel wie 2! Die Faustregel lautet: wenn Du etwas in einer Zählschleife
oder in einer Schleife mit Abbruchbedingung erledigen kannst, dann nimm die Zählschleife. Die ist
kürzer und besser verständlich!
159
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
7.4.1. Zähl-Schleifen
5,4,3,2,1
Cassius Clay you’d better run
99, 100, 101, 102
Your mother won’t even recognize you
—Bob Dylan 7
Behandeln wir also zuerst die Zählschleife. In Python stellt man sich diese Art von Schleifen so vor:
hier bekommst Du (die Schleife) eine Menge von Dingen, und mit jedem dieser Dinge mach etwas. Das
kann eine Menge von Zahlen, eine Menge von Namen, eine Menge von irgendwelchen Objekten sein.
Bei einer Zählschleife gibt es eine Variable, die Buch darüber führt, wie oft etwas gemacht werden
soll und wo man denn schon steht. Wenn die Menge von Dingen Zahlen sind, wird eine solche Variable
Zähler“ genannt. Einem solchen Zähler muss man mitteilen,
”
1. was der Anfangswert der Zählung sein soll,
2. was der Endwert sein soll und
3. mit welcher Schrittweite gezählt werden soll.
Eine Möglichkeit, über eine Menge von Zahlen zu schleifen, ist mittels des range-Objekts.8 Ein
range-Objekt ist eine Konstruktionsvorschrift, die beim Aufruf jeweils das nächste Element erzeugt.
Das range-Objekt wird erzeugt, indem ihm
1. entweder der Endwert als Parameter
2. oder der Anfangswert und der Endwert
3. oder der Anfangswert, der Endwert und die Schrittweite
übergeben werden.
Das englische Wort range“ bedeutet Bereich. Wenn nur ein Wert angegeben ist, wird als Standard-
”
Startwert die 0“ angenommen. Das freut den Mathematiker, denn die natürlichen Zahlen fangen bei
”
0“ an. Ebenso wird angenommen, dass der dritte Wert, die Schrittweite, wenn er nicht angegeben ist,
”
1“ ist. Außerdem sieht man im unten stehenden Beispiel, dass der bereichx (mit x ∈ {1; 2; 3} ) ein
”
Objekt ist, das eine Konstruktionsbeschreibung für eine Liste enthält. Mit print wird diese Konstruk-
tionsbeschreibung ausgeben, mit list wird die Liste erzeugt.
160
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
In der folgenden Tabelle wird gegenübergestellt, wie sich ein einfacher Algorithmus, der in der lin-
ken Spalte in Pseudocode“ beschrieben ist, fast eins zu eins in Python übertragen lässt. Das ist das
”
Beispiel vom Anfang des Kapitels. Auch hier gilt wieder: wer das Problem richtig durchdenkt und klar
formuliert, der schreibt das dazugehörige Python-Programm sehr schnell.
Hier finden wir wieder die Einrückung, die wir aus dem Kapitel über die Alternative kennen. Der
Aufruf der print-Funktion ist abhängig von der Zählung; also muss er eingerückt werden und das,
wovon abhängig ist, wird durch einen Doppelpunkt abgeschlossen. Das sollte man jetzt, sofern man
vor seinem Rechner sitzt, selber probieren.
W ICHTIG
Zwei Sachen muss man hier beachten. Zum einen startet die Zählung bei 0. Aber
das sind wir ja schon fast gewohnt. Zum anderen gilt hier wie beim Slicing von
Zeichenketten, dass der Anfangswert mit ausgegeben wird, der Endwert jedoch
nicht.
Jetzt probieren wir gleich etwas mehr aus, indem wir der range 2 Werte mitgeben. Werte werden
durch Kommata voneinander getrennt, wohingegen das deutsche Dezimalkomma in englischsprachi-
gen Ländern zum Dezimalpunkt wird.
Man sieht: der erste Wert gibt den Anfang der Zählung, der zweite das Ende der Zählung an.
161
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Der dritte Wert gibt also die Schrittweite an. Also können wir endlich der NASA behilflich sein, und
das Countdown-Programm schreiben:
Da nicht nur Zahlen gezählt werden können, wie wir inzwischen wissen, sondern auch Listen(-
Elemente), kann man auch über Listen schleifen:
Mit den beiden Sprachelementen aus den letzten beiden Absätzen kann man sich nochmal veran-
schaulichen, wie die Hausnummern mit den Elementen zusammenhängen. Im folgenden Code-Segment
wird die Hausnummer und das Element jeweils ausgegeben:
162
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
0 1
1 2
2 3
3 4
4 5
5 6
Alles klar? Die Länge der Liste ist 6, die range, geht also genau von 0 bis 5, und das sind die Haus-
nummern der Elemente der Liste. Jetzt hat wahrscheinlich jeder verstanden, warum es
2. dass das Endelement einer range nicht mehr mit bearbeitet wird
Zählschleifen können aber auch benutzt werden bei Strukturen wie Zeichenketten, denn eine Zeichen-
kette ist (siehe oben bei String als Feld) im Prinzip nichts anderes als ein Feld, das durchnummeriert ist,
und das man deswegen abzählen kann.
Das ist gut, aber noch besser wäre es, wenn alles in einer Zeile stünde. Auch das ist einfach zu rea-
lisieren, denn ich muss Python nur mitteilen, dass es nach einem Aufruf von print keinen Zeilenvor-
schub machen soll. Dies geschieht dadurch, dass man der den print-Funktion als zusätzlichen Parameter
end=’ ’ mitgibt.
163
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Abele
Bbele
Cbele
Dbele
Als letztes Beispiel soll hier, wieder in einer Gegenüberstellung von Pseudocode und Python-Code,
der (Noten-)Durchschnitt einer Klasse berechnet werden. Der Lehrer weiß zwar, dass in der Klasse 25
Schüler sind, aber aus allgemein bekannten Gründen sind bei einer Klassenarbeit nicht zwingend alle
Schüler anwesend. Trotzdem ist das kein Problem. Seien also ganz einfach alle Noten dieser Klassenar-
beit in einer Liste gespeichert notenL = [2.5, 3.6, 1.7, 4.2, 5.5, 5.2, 1.6] (ok, da fehlen
aber heute viele!!! Egal, ich bin zu faul, da mehr reinzuschreiben, und das Programm soll auch funktio-
nieren, gleich wieviele Elemente in der Liste sind).
Das Programm ist gut! Mit einer überschaubaren (sogar endlichen) Anzahl von Programmzeilen kann
ich eine nicht mehr so gut überschaubare Anzahl von Daten bearbeiten. Umgangssprachlich würde man
wohl behaupten, dass die Notenliste unendlich viele Noten enthalten könnte, als Mathematiker muss
man natürlich genau sein und sagen, dass die Notenliste beliebig lang sein kann. Ich habe sogar mehr
erreicht, als ich ursprünglich vorhatte. Die erste Idee war, dass in der Notenliste immer die Noten aller
Schüler stehen, dass die Länge der Liste also fest ist. Python ist aber in der Lage, mit einfachen Mitteln
eine Liste beliebiger Länge abzuarbeiten.
Weil das Mitzählen, oben durch den Zähler anzSchueler erledigt, einfach ist, aber immer wieder
benötigt wird, ist so etwas natürlich in Python integriert. Man könnte das Programm vereinfachen,
indem man die Methode len(liste) aufruft. Diese gibt die Anzahl der Elemente der Liste, hier also
die Anzahl der Schüler, die die Klassenarbeit mitgeschrieben haben, zurück.
Es fehlt aus dem Kapitel über strukturierte Daten noch das Beispiel, wie man eine Matrix schön dar-
stellt.
164
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
def matrixDarst(m):
print(’ ’)
for zeile in m:
spTupel = ()
anzSpalten = len(zeile)
for spalte in zeile:
spTupel = spTupel + (spalte, )
print("%+6.4f\t"*anzSpalten % spTupel)
Der Trick dabei ist, die Liste in ein Tupel zu verwandeln, das man an einen Formatstring übergibt.
Dabei wird der Formatierungsbefehl genau so oft wiederholt, wie es Anzahl Spalten gibt.
Auch Dictionaries können in einer Zähl-Schleife abgearbeitet werden, allerdings ist hierbei nicht klar,
in welcher Reihenfolge. Das kann aber manchmal ganz geschickt sein, zum Beispiel, wenn man ein
Ratespiel programmiert. Dieses Spiel hier hilft vielleicht beim Vokabellernen. Es gibt den englischen
Begriff aus und fragt die deutsche Übersetzung ab:
Das Spiel könnte noch dadurch erweitert werden, dass es hinzulernt, etwa dadurch, dass ein Begriff,
der noch nicht im Dictionary enthalten ist, weil eine falsche Antwort gegeben wurde, eingefügt wird.
Eine nette Übungsaufgabe!
Manchmal ist es wünschenswert, dass Python sein Wissen, bei dem wievielten Element innerhalb einer
Zählschleife es sich gerade befindet, nicht für sich behält, sondern ausgibt. Dazu dient die Funktion
enumerate. Als Beispiel wird hier eine Liste von Namen genommen, bei der durch eine Zählschleife
nicht nur der Name, sondern auch die Position des Namens in der Liste ausgegeben werden soll.
165
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Ein ähnliches Problem ist, dass ich in einer Schleife zwei Sachen machen will: rechnen und zählen.
Ein Beispiel: ich habe eine Liste mit Zahlen und ich will zum einen wissen, wie lang die Liste ist, und
zum anderen, wie groß die Summe der Zahlen in der Liste ist.
Hier benutze ich, dass Python in einer Anweisung mehrere Wertzuweisungen machen kann.
7.4.2. While-Schleifen
Oft soll aber nicht gezählt geschleift“ werden, sondern man soll einen Block von Anweisungen solange
”
wiederholen, bis eine bestimmte Bedingung erreicht ist. Um wieder den Vergleich eines Algorithmus
mit einem Kochrezept hervorzuholen: da gibt es so etwas sehr häufig:
166
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Auch hier wird in einer Tabelle gegenübergestellt, wie das einfache Beispiel vom Anfang des Kapitels
in Pseudocode und in Python ausgedrückt wird. Der Algorithmus, der in der linken Spalte in Pseudo-
”
code“ beschrieben ist, kann fast eins zu eins nach Python übertragen werden.
Das hier beschriebene Programm-Segment ist ein typischer Fall für eine While-Schleife. Einen Pro-
grammablauf kann man so steuern:
pass ist eine Anweisung, die Python auffordert, nichts zu machen. Das ist manchmal sehr sinn-
voll, denn wie in dem obigen Beispiel will (oder soll) man alle möglichen Eingaben in ein Programm
berücksichtigen, aber in diesem einen Fall einer korrekten Eingabe nichts machen. Eine andere Anwen-
dung für die pass-Anweisung ist, dass man bei einem längeren Projekt einen möglichen Programm-
zweig noch nicht programmiert hat. Die Alternative zu der Anweisung pass ist die Anweisung ....
Eine gute Vereinbarung mit sich selbst könnte lauten:
• pass verwende ich, wenn hier wirklich nichts passieren soll. Nie!!!
• ... verwende ich, wenn ich im Laufe der Entwicklung hier noch etwas schreiben werde
Man zeigt an, dass hier etwas passieren wird, indem man die Möglichkeit öffnet, aber man schreibt die
leere Anweisung hin, weil man noch nicht weiß, was passieren wird.
Ein anderer klassischer Fall für eine While-Schleife ist das Lesen einer Datei. Da bisher noch keine
Datei-Behandlung besprochen wurde, wird der Programmcode nicht in Python, sondern in Pseudocode
wiedergegeben:
while nochEtwasVorhanden:
liesEinZeichen
if keinZeichenMehr:
dannHoerHaltAufMitLesen
167
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
[Link]. Listen oder Dictionaries durch eine Art Liste erzeugen (list comprehensions)
List comprehensions sind Ausdrücke, die aus einer Kombination von Listen und Schleifen bestehen, um
daraus eine neue Liste zu machen. Als einfaches Beispiel soll eine Liste aller Quadratzahlen zwischen 0
und 100 erstellt werden, das Ergebnis unserer Arbeit soll also q = [0,1,4,9,16,25,36,49,64,81]
sein. Natürlich könnte man für eine solch einfache Liste seinen Editor nehmen und sie von Hand erstel-
len. Aber das ist nicht schön!
Eleganter ist es, eine Liste zu schreiben, die einen Ausdruck enthält. Und diese Eleganz ist in Python
unübertroffen:
q ist unsere neue Liste, die dadurch entsteht, dass das Quadrat jeder Zahl zwischen 0 und 10 gebildet
wird. Man kann sich die obige erste Programmzeile auch laut vorlesen: q ist die Liste aller Zahlen,
die dadurch gebildet werden, dass man nacheinander die Quadrate aller Zahlen zwischen 0 und 10
berechnet. Python ist wirklich eine schöne weil einfache Sprache.
168
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Ein nächstes Beispiel: die Wertetabelle der natürlichen Exponentialfunktion für den Bereich von -2 bis
1:
Das geht noch umfangreicher! Ich brauch jetzt eine Liste der Punkte im cartesischen Koordinatensys-
tem, deren Koordinaten ganze Zahlen sind. Also muss ich Paare erstellen, auch über die y-Koordinate
geschleift werden muss (der Mathematiker würde das kurz als cartesisches Produkt bezeichnen, wobei
sowohl über die x-Koordinate als auch über die y-Koordinate geschleift wird).
Wenn ich eine Matrix, also eine Liste von Listen, erzeugen will, ist das auch über eine list comprehen-
sion in einer Zeile zu erreichen:
169
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Da es tatsächlich funktioniert, Listen durch list comprehensions, die eine geschachtelte Schleife ent-
halten, zu erzeugen, sollte es auch möglich sein, ein Dictionary auf diese Art zu erstellen. Die Buchstaben
eines Textes auf ihre Häufigkeit zu untersuchen ist eine Anwendung dieses Problems. Der Programm-
code sollte selbstredend sein.
Und jetzt soll noch aus einem Text ein Dictionary erzeugt werden. Ein Datum ist als Zeichenkette
gegeben (in der üblichen deutschen Schreibweise), daraus soll ein Dictionary gebaut werden.
Alles klar?
170
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Anfang aufgerufen; schaun wir mal, ob wir das mittels einer Schleife auch rauskriegen. Diese Schleife
zu programmieren hilft aber, viele ähnliche Probleme zu verstehen und zu lösen.
liste = [7,12,5,23,1,14,18,33,4]
print(len(liste))
zaehler = 0
for i in liste:
zaehler += 1
print(zaehler)
Das ist wohl nicht so schwer zu verstehen! Vor Beginn der Schleife wird eine Variable Zähler deklariert
und auf 0 gesetzt. Dann wird die Schleife Element für Element gelesen; bei jedem Schleifen-Durchlauf
wird der Zähler um 1 hochgezählt.
[Link]. Anzahl der Elemente einer Liste mit einer bestimmten Eigenschaft
Bei diesem Problem hilft die len-Funktion nicht mehr! Aber es ändert sich gar nicht so viel an dem
vorigen Programm. Einzig innerhalb der Schleife wird gefragt, ob das aktuelle Element die Bedingung
erfüllt, und nur wenn es das tut, wird der Zähler erhöht.
liste = [7,12,5,23,1,14,18,33,4]
zaehler = 0
for i in liste:
if i % 3 == 0:
zaehler += 1
print(zaehler)
Alles klar? Wenn nicht, lies noch mal die Einführung zu diesem Beispiel und die Erklärung zum
vorigen Beispiel.
Also führen wir eine zweite Liste ein, die zu Beginn leer ist. Wenn die Bedingung erfüllt ist, wird mittels
der append-Methode von Listen diese Liste erweitert.
171
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Beispiel 7.4.33 Anzahl der durch 3 teilbaren Zahlen in der Liste mit Ergebnisliste
#!/usr/bin/python
liste = [7,12,5,23,1,14,18,33,4]
ergListe = []
zaehler = 0
for i in liste:
if i % 3 == 0:
zaehler += 1
[Link](i)
print(zaehler)
print(ergListe)
Sei also eine Liste von Elementen gegeben, für die es ein Ordnungskriterium gibt, so dass man also das
größte Element bestimmen kann. Der Einfachheit halber ist dies eine Liste von natürlichen Zahlen, auf
denen die übliche Größer-Relation definiert ist.
liste = [7,12,5,23,1,14,18,33,4]
max = liste[0]
for i in liste[1:]:
if i > max:
max = i
print(max)
Die Logik ist wohl leicht zu erkennen: bevor die Schleife aufgerufen wird, wird das Maximum mit
dem ersten (erinnere Dich: das ist das Element mit der Hausnummer 0) Element der Liste initialisiert.
Dann wird die Schleife über die Liste ab dem zweiten Element durchlaufen. Jedes Element wird mit dem
Maximum verglichen, und wenn das jeweils in Arbeit befindliche Element größer ist als das aktuelle
Maximum, wird dieses aktuelle Element zum Maximum.
Im Gegensatz zum vorigen Beispiel interessiert nicht das größte Element, sondern nur die Position, an
der dieses in der Liste steht.
172
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
liste = [7,12,5,23,1,14,18,33,4]
max = liste[0]
pos = 0
for i in range(1, len(liste)):
if liste[i] > max:
pos = i
print(pos)
Eine vollständig andere Logik für die Schleife muss hier angewendet werden. Vor Beginn des Schlei-
fendurchlaufs wird wieder das Maximum mit dem ersten Element initialisiert, zusätzlich dazu wird die
Position mit 0 besetzt. Es kann aber jetzt nicht mehr über die Liste als solche geschleift werden, sondern
hier muss, da die Position interessiert, über die Zahl, die die Länge der Liste angibt, geschleift werden.
Sortieren sollte man können! Vor langer Zeit, ungefähr in der zweiten Hälfte des 20. Jahrhunderts, gab es
wohl kaum ein Buch zur Informatik, in dem nicht auf die verschiedenen Möglichkeiten des Sortierens
eingegangen wurde. Das will ich hier nicht, aber wenigstens die Problematik anreissen. Nehmen wir
an, ich habe eine endliche Menge von Dingen, die nach einem bestimmten Kriterium sortiert werden
sollen: Bücher nach dem Nachnamen, dann dem Vornamen des Autors, und falls der mehrere Bücher
geschrieben hat, auch noch nach dem Erscheinungsjahr; Rock-Platten nach der Band (für schwäbische
Rock-CD’s: der Kapelle9 ), dann nach dem Erscheinungsjahr. Alle diese Probleme benötigen natürlich
eine Methode, um zwei Exemplare nach dem jeweiligen Vergleichskriterium zu vergleichen.
Da ich nicht auf diese Vergleichskriterien eingehen will, vereinfache ich das Problem dadurch, dass
ich als Dinge ganze Zahlen wähle, und dass diese nach der Größe sortiert werden sollen. Da bietet es
sich natürlich an, diese Dinge in eine Liste zu schreiben, womit die Aufgabe verkürzt so formuliert wird:
sortiere doch mal bitte diese Liste aufsteigend:
liste1 = [13,5,8,51,23,41,1,55,36,3,64,7,52,37,32,6,42,38,53,2,12,9,47,39,24,43,21,17]
Eines der historisch ersten Verfahren ist unter dem Namen Bubblesort“ bekannt. Der Name kommt
”
daher, dass bei diesem Verfahren (je nach Vorgehen) die größten oder kleinsten Elemente wie Luftblasen
aufsteigen. Und es funktioniert so:
Das soll einmal an einer kürzeren Liste von Hand begonnen werden.
173
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
l2 = [13,5,8,51,23,41,1,55,36,3,64,7,52,37,32,6,42,38,53,2,12,9,47,39,24,43,21,17]
sortiert = False
• eine gegebene andere Funktion mit den ersten beiden Elementen des abzählbaren Objekts aus und
gibt das Ergebnis dieser Funktion zurück,
174
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
• nimmt dann dieses Ergebnis und das dritte Element, führt wieder die Funktion aus und gibt das
neue Ergebnis zurück
• nimmt dieses neue Ergebnis und das vierte Element ... usw.
Ein Beispiel veranschaulicht das sofort (auch wenn Funktionen in Python noch nicht besprochen wur-
den; aber das folgt innerhalb der nächsten Seiten):
Das macht die Funktion, wenn man ihr zwei Dinge übergibt:
Beispiel 7.4.42 reduce mit dieser Funktion und einer Liste von Zahlen
reduce(summe, [1,2,3,4,5])
1 + 2
3 + 3
6 + 4
10 + 5
15
175
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
2 zahlenListe = [1,5,523,274,143,76,15,72,2456,1,13,752,3416,6134,3475,374,
3 347,4612,57834,437]
4 summe = 0
5 gefundenZaehler = 0
6 for zahl in zahlenListe:
7 if zahl % 2 == 1:
8 continue
9 else:
10 if gefundenZaehler < 5:
11 summe += zahl
12 gefundenZaehler += 1
13 else:
14 break
15
16 print(summe)
17 (gibt aus) 3630
18 print(gefundenZaehler)
19 (gibt aus) 5
20
In Zeile 6 wird gefragt, ob der Rest bei der Division einer Zahl durch 2 gleich 1 ist, also ob die Zahl
ungerade ist. Wenn ja, dann wird durch den Befehl continue der Durchlauf der Schleife abgebrochen,
zum Ende des Schleifenkörpers gesprungen und mit der nächsten Zahl weitergemacht. Wenn das nicht
der Fall ist, wird gefragt, ob der Zähler für die gefundenen geraden Zahlen noch kleiner als 5 ist. Wenn
ja, wird die aktuelle Zahl auf die Summe aufsummiert und der Zähler für die gefundenen Zahlen um 1
erhöht. Wenn der Zähler nicht mehr kleiner als 5 ist, wird durch den Befehl break die gesamte Schleife
sofort beendet.
176
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
Das ist der weniger schlimme Fehler: zu Beginn der Schleife ist die Variable x nicht bekannt, weil
ihr bisher kein Wert zugewiesen wurde. Weniger schlimm ist das deshalb, weil das Programm an die-
ser Stelle einfach mit dem Fehler NameError: name ’x’ is not defined abbricht. Damit ist der
Fehler schnell korrigiert.
Jetzt hat die Variable x vor Beginn der Schleife einen Wert, und der ist so gewählt, dass die Bedingung
nach dem while erfüllt ist: die Schleife startet und gibt den Wert 7 aus. Danach geht das Programm
wieder zum Schleifenbeginn zurück, der Wert der Variablen x ist 7, die Schleife wird ausgeführt usw.
und so fort, und wenn sie nicht gestorben sind, schleifen sie noch immer. So etwas wird Endlosschleife“
”
genannt. Jetzt gibt es nur 2 Möglichkeiten: wenn man Glück hat, kann man noch in irgendeiner Form
das Programm abbrechen, wenn nicht, kann man nur noch den Rechner ausschalten.
Merke also: Bei Schleifen mit Abbruchbedingung muss die Variable, die die Schleife steuert, vor dem
Beginn der Schleife initialisiert sein; innerhalb der Schleife muss der Wert dieser Variablen verändert
werden (und zwar so, dass irgendwann die Bedingung nicht mehr erfüllt ist).
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
*********************
***********************
*************************
***************************
*****************************
*******************************
*********************************
***********************************
*************************************
4. Ein Programm soll die Quadratzahlen bis zu einer bestimmten Grenze ausgeben.
5. Aufgabe mit der Ausbreitung einer Epidemie:
a) n = Bevölkerung (konstant)
b) x(t) = Gesunde zur Zeit t
177
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
178
KAPITEL 7. PROGRAMMSTRUKTUREN 7.4. SCHLEIFEN
23. Heutzutage kommt man nicht mehr umhin, in einem Text über Programmierung auch auf Ver-
und Entschlüsseln zu sprechen. Schreibe ein Programm, das eine monoalphabetische Verschlüsselung
eines Textes liefert, so wie sie der Legende nach auf Caius Iulius Caesar zurückgeht. Caesar soll
damals einfach um eine bestimmte Zahl im Alphabet weitergezählt haben. Beispiel: Wenn diese
Zahl die 3 war, dann wurde aus A ein D, aus H ein K etc.
Dabei sei der Text, wie damals zu Cäsars Zeit, in reinen Großbuchstaben gegeben. Der verschlüsselte
Text soll auch nur Großbuchstaben enthalten. Leerzeichen bleiben Leerzeichen, Satzzeichen wer-
den erhalten.
a) Die einfache Variante arbeitet mit einer Zeichenkette, die nach Buchstaben durchsucht wird.
Diese Zeichenkette muss einige Buchstaben doppelt enthalten.
b) Die nächstschwierige Variante arbeitet modulo der Länge des Alfabets.
c) Die komfortable Lösung erlaubt auch Kleinbuchstaben und Sonderzeichen. Für diese Lösung
werden zwei Funktionen benötigt: ord(Zeichen) liefert die Nummer des Zeichens zurück,
chr(Zahl) liefert das Zeichen mit der Nummer Zahl zurück.
Ein Tip: geh in IDLE, schau nach, was A für eine Hausnummer hat!
24. Eine verbesserte Methode ist die Verschlüsselung mit Schlüsselwort. Dabei verschiebt man nicht
jeden Buchstaben um den selben Wert, sondern denkt sich ein Schlüsselwort aus. Hier wird das
beispielhaft mit einem sehr kurzen Schlüsselwort, dem Wort BAD“, gemacht.
”
B ist der zweite Buchstabe des Alfabets, A der erste, D der vierte. Es gibt also folgende einfache
Zuordnung:
Wenn jetzt der Text EIN GEHEIMER BRIEF“ verschlüsselt werden soll, dann geschieht das fol-
”
gendermaßen (der Einfachheit halber ignoriere ich in diesem Beispiel die Leerzeichen):
a) Der erste Buchstabe des Textes, das E wird mit dem Buchstaben B, dem ersten Buchstaben
des Schlüsselwortes, verschlüsselt. B hat den Wert 2, also wird von E aus zwei Buchstaben
weitergezählt.
b) Der zweite Buchstabe des Textes, das I wird mit dem Buchstaben A, dem zweiten Buchsta-
ben des Schlüsselwortes, verschlüsselt. A hat den Wert 1, also wird von I aus ein Buchstabe
weitergezählt.
c) Der dritte Buchstabe des Textes, das N wird mit dem Buchstaben D, dem dritten Buchstaben
des Schlüsselwortes, verschlüsselt. D hat den Wert 4, also wird von N aus vier Buchstaben
weitergezählt.
d) Der vierte Buchstabe des Textes, das G wird mit dem Buchstaben B, dem ersten Buchstaben
des Schlüsselwortes, verschlüsselt (denn da das Schlüsselwort nur 3 Buchstaben hat, geht es
hier wieder von vorne los). B hat den Wert 2, also wird von G aus zwei Buchstaben weiter-
gezählt.
e) usw.
Es lohnt sich, genau hinzuschauen! Der 0. und der 4. Buchstabe im Originaltext sind jeweils ein
E“, aber das E“ an Position 0 wird zu einem G“, das an Position 4 zu einem F“. Der Geheimtext
” ” ” ”
an Stelle 4 ist ein F“, ebenso der an Stelle 11. Der Originaltext ist aber unterschiedlich ( E“ bzw.
” ”
B“). Es gibt also keine eindeutige Zuordnung mehr!
”
179
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
7.5. Funktionen
7.5.1. Allgemeines zu Funktionen
Oft ist eine bestimmte Anweisungsfolge nicht für einen Wert, sondern für mehrere Werte zu durchlau-
fen. Es ist also praktisch, dieser Anweisungsfolge einen Namen zu geben, unter dem sie aufgerufen
werden kann. Ideal ist es, wenn man beim Aufruf dieser Anweisungsfolge unter einem vorher festge-
legten Namen noch einen oder mehrere Werte mitgeben kann. Das ist das Prinzip einer Funktion. Die
Werte, die man einer solchen Funktion mitgibt, werden Parameter“ genannt.
”
Dadurch gewinnt man. Man gewinnt Zeit: ein Stück Code muss nur einmal geschrieben werden. Man
gewinnt Freunde: jemand anderer kann den Code benutzen, wenn er gut funktioniert. Man gewinnt
Ordnung: das, was ich in einer Funktion codiert habe und von dem erwiesen ist, dass es funktioniert,
kann ich wegräumen“, so dass ich es nicht immer wieder lesen muss.
”
Funktionen kennt wahrscheinlich jeder aus der Mathematik. Dort sieht eine Funktion zum Beispiel so
aus: f (x) = 2x2 − 3x + 5 Die Funktion hat einen Namen, nämlich f“ 10 , es gibt eine Variable, das x, das
”
sozusagen in die Funktion eingegeben wird, und es gibt einen (Rückgabe-)Wert, der aus der Funktion
herausgegeben wird, nämlich das, was auf der rechten Seite des Gleichheitszeichens ausgerechnet wird,
wenn man für x einen Wert eingibt. Als Beispiel: wenn man in die oben notierte Funktion den Wert 2
eingibt, berechnet die Funktion 2*4 - 3*2 +5 und gibt als Ergebnis 7 zurück. Wer etwas mehr Mathematik
gemacht hat als die normale Oberstufen-Mathematik, der weiß auch, dass es Funktionen gibt, die mehr
als eine Variable haben.
In einigen Programmiersprachen werden solche abgeschlossenen Blöcke von funktionierenden An-
”
weisungen“ auch Unterprogramme oder Prozeduren genannt, während Funktionen Unterprogramme
sind, die einen Wert zurückgeben. In Pascal etwa gibt es verschiedene Schlüsselwörter für Prozedu-
ren und Funktionen. In anderen Programmiersprachen hingegen werden die Begriffe gleichbedeutend
benutzt.
180
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
• einen Funktionsnamen
• einen Funktionskopf
• einen Funktionskörper
• und manchmal einen Rückgabewert (den Funktionswert)
Für den Funktionsnamen gelten alle Regeln, die für Variablennamen (siehe dort) gelten. Es ist guter Stil,
wenn man Funktionen als Namen ein Verb gibt, denn Funktionen tun etwas. Auch hier ist ein Vergleich
mit der Mathematik interessant: in der Mathematik heißen Funktionen fast immer f“, während in der
”
Programmierung der Funktionsname schon Aufschluss darüber geben sollte, was die Funktion macht.
In Mathematik berechnet eine Funktion immer einen Wert. In der Programmierung macht eine Funktion
irgendwas.
Der Funktionskopf besteht aus dem reservierten Wort def“, gefolgt vom Funktionsnamen und Para-
”
metern, die in Klammern mitgegeben werden. Selbst wenn einer Funktion keine Parameter mitgegeben
werden, muss ein leeres Paar Klammern geschrieben werden. Der Funktionskopf endet mit einem Dop-
pelpunkt, und inzwischen ist bekannt, was nach dem Doppelpunkt gemacht werden muss: die Anwei-
sungen, die zur Funktion gehören, der Funktionskörper, müssen eingerückt werden. Da es (vor allem zu
Beginn der Entwicklung eines Programms) vorkommt, dass man weiß, dass ein Teil der Problemlösung
durch eine Funktion erledigt werden soll, man aber sich noch nicht mit deren Details auseinandersetzen
will, ist es praktisch, eine Funktion zu schreiben, die nichts tut. Dies geschieht durch die Anweisung
pass:
Aber hier folgt gleich ein einfaches Beispiel, das etwas tut:
Damit hat man eine Funktion definiert, und es ist klar, was sie leistet. Jetzt kann man diese Funktion
aufrufen:
Diese Funktion hat also keinen Parameter (keine Variable, die etwas in die Funktion reinbringt) und
keinen Rückgabewert, das heißt, es kommt auch nichts aus der Funktion heraus.
Wie vorher schon erwähnt, ist es besonders hilfreich, wenn eine Funktion nicht immer das selbe
macht, sondern abhängig von einem mitgegebenem Wert etwas tut. Ein solcher Wert wird Parameter
oder Argument der Funktion genannt. Also bohren wir das obige Beispiel auf, so dass der Gruss etwas
persönlicher wird:
181
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Wie weiter oben angesprochen kommt hier eine Funktion, die ausgibt, ob eine Zahl zwischen zwei
anderen Zahlen liegt.
Und die letzten 3 Zeilen wundern auch nicht mehr: Python kann auch zum Beispiel überprüfen, ob ein
Buchstabe zwischen zwei anderen liegt. Hier sollte man vielleicht einmal probieren, ob diese Funktion
auch mit anderen Daten als Zahlen und Buchstaben klar kommt.
Bis jetzt hat eine Funktion etwas gemacht, nicht mehr und nicht weniger. In mancher anderen Program-
miersprache11 wird so etwas Prozedur“ genannt. Funktionen unterscheiden sich in diesen Sprachen
”
von Prozeduren, dass sie etwas zurückgeben. Das soll an einem einfachen Beispiel vorgeführt werden.
Dazu muss man nichts sagen! Beim Aufruf dieser Funktion wird einfach die Summe der beiden Pa-
rameter ausgegeben.
11 z. B. in den Wirth-Sprachen
182
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Jetzt soll eine Funktion diese Summe zurückgeben. Das reservierte Wort, das einen Rückgabewert
zurückgibt, heißt return“. So sieht das aus:
”
Es folgt ein weiteres Beispiel dazu, und zwar sowohl die Definition als auch die Ausführung:
Hier hingegen wird etwas in die Funktion reingegeben und es kommt auch ein Rückgabewert heraus.
Dabei ist es der Funktion egal, welcher Art die Daten sind, die ihr übergeben werden:
Wie weiter oben schon erwähnt wurde, kann eine Funktion auch mehrere Parameter bekommen.
183
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Hier ist es natürlich wichtig, dass beim Aufruf der Funktion die Werte für die Parameter in der selben
Reihenfolge übergeben werden, wie sie die Funktion in ihrem Funktionskopf deklariert hat, also in
diesem Beispiel in der Reihenfolge Vorname, Nachname, Telefonnummer.
Es ist allerdings möglich, von dieser eben beschriebenen Regel abzuweichen, indem man beim Aufruf
einer Funktion nicht nur den Wert für einen Parameter mitgibt, sondern im Aufruf der Funktion dem
Parameternamen einen Wert zuweist. Das obige Beispiel lässt sich also auch so schreiben:
Hier wird also die Reihenfolge, wie sie in der Parameterliste des Funktionskopfes vorgegeben ist,
nicht eingehalten, sondern die Reihenfolge wird beliebig gewählt, dafür aber bei jedem Parameterwert
mitgeteilt, welchem Parameter dieser Wert zugewiesen werden soll.
Oft weiß man, dass für einen Parameter fast immer ein bestimmter Wert übergeben wird; das wird
in der Informatik als Default-Wert“ bezeichnet. Dann ist es gut, wenn man in der Parameterliste einer
”
Funktion schon einen Standardwert festlegen kann. Das bedeutet, dass man für diesen Parameter der
Funktion einen Wert an die Funktion übergeben kann (dann wird der genommen), es aber auch sein
lassen kann (dann wird der in der Parameterliste festgelegte Standardwert genommen). Das Beispiel
dazu:
Und, kein Wunder, das funktioniert natürlich auch mit einer Zahl als Wert für den ersten Parameter:
184
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Es gibt sogar die Möglichkeit, Funktionen zu schreiben, bei denen die Anzahl der Parameter unbe-
kannt ist. In einem solchen Fall übergibt man der Funktion ein Tupel von Werten. Die spannende Frage
ist, wie die Funktion dieses Tupel entgegennimmt. Dies geschieht dadurch, dass dem Parameternamen
in der Klammer der Funktionsdefinition ein *“ vorangestellt wird. Das Beispiel dazu sieht so aus:
”
Den ersten beiden Parametern, beide ohne einen *“ in der Funktionsdefinition, werden also die ers-
”
ten beiden Werte des Tupels zugewiesen. Dem letzten Parameter, dieser mit *“, wird der gesamte Rest
”
zugewiesen. Dieser gesamte Rest ist somit wieder ein Tupel, das aus diesem Grund in Klammern ge-
schrieben wird, wobei die einzelnen Teile des Tupels in Anführungsstriche gesetzt und durch Kommata
voneinander getrennt sind.
Mit diesem Wissen ist es aber auch einfach, die Parameter, auch die aus dem Tupel, einzeln auszuge-
ben:
Wenn einer Funktion Schlüsselparameter übergeben werden, also Parameter mit Parameternamen,
dann soll daraus ein Dictionary gemacht werden. Das geschieht mit den **“. Die Erklärung ergibt sich
”
aus dem folgenden Beispiel:
185
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
def quadrieren(z):
return z*z
zahl = 3
zwischenergebnis = verdoppeln(zahl)
endergebnis = quadrieren(zwischenergebnis)
print(endergebnis)
>>> 36
Das funktioniert! Aber es sieht nicht schön aus. Die beiden Funktionen sind kurz, der Name sagt aus,
was sie jeweils machen, also bleiben die beiden Funktionen so. Der Aufruf hingegen kann verbessert
werden. Also vereinfachen (und verschönern) wir das:
def quadrieren(z):
return z*z
zahl = 3
endergebnis = quadrieren(verdoppeln(zahl))
print(endergebnis)
>>> 36
Den Mathematiker freut es, denn so schreibt er auch die Verkettung von Funktionen. Wenn zuerst die
Funktion f1 mit dem Argument x und dann die Funktion f2 mit dem Ergebnis der ersten Funktion als
Argument aufgerufen werden soll, dann schreibt der Mathematiker f2 (f1 (x))
An dieser Stelle kommt der Begriff Namensraum ins Spiel. Der Namensraum ist der Bereich, in dem eine
Variable (oder ein anderer Teil eines Programms) bekannt und gültig ist. Das wird deswegen auch der
Gültigkeitsbereich genannt. Das war bis jetzt noch kein Problem, weil unsere Programme noch nicht in
kleinere Einheiten unterteilt waren.
Eine Funktion ist aber ein kleines Programm im Programm“, womit eine solche Unterteilung in
”
kleinere Einheiten geschieht. Damit gilt auch, dass eine Variable, die erst innerhalb einer Funktion zum
ersten Mal benutzt wird, dadurch, dass ihr ein Wert zugewiesen wird, außerhalb der Funktion nicht
bekannt ist. Das wird in der Programmierung eine lokale Variable genannt. Ein einfaches Beispiel, um
das zu demonstrieren, sieht so aus:
186
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
def doofFunktion():
nr = 378
print(’Nummer IN der Funktion:’, nr)
doofFunktion()
print(’Nummer NACH der Funktion:’, nr)
Die Variable nr wird hier in der Funktion definiert und gleich ausgegeben. Nach Beendigung der
Funktion wird nochmals versucht, diese lokale Variable auszugeben. Hier ist die Ausgabe des Pro-
gramms:
Wie man sieht, wird der print-Befehl nach Beendigung der Schleife nicht ausgeführt, weil die Varia-
ble nr außerhalb der Funktion nicht bekannt ist, sondern das Programm bricht mit einer Fehlermeldung
ab.
Die Variable, die innerhalb der Funktion definiert wird, gehört zum Gültigkeitsbereich der Funktion.
Hier ist sie bekannt, außerhalb nicht. Anders sieht es aus, wenn eine Variable im Hauptprogramm de-
finiert wird. Eine solche Variable gehört zum Gültigkeitsbereich des Hauptprogramms und damit auch
zum Gültigkeitsbereich aller Funktionen, die innerhalb des Hauptprogramms definiert werden. Man
nennt eine solche Variable, die im ganzen Programm gültig ist, eine globale Variable“. Das soll an
”
einem Beispiel verdeutlicht werden:
def innereFktErsterEbene():
var1E = ’\tVariable der 1. Ebene’
print(var1E)
print(’\tAufruf aus 1. Ebene: ’+varHauptPgm)
def innereFktZweiterEbene():
var2E = ’\t\tVariable der 2. Ebene’
print(var2E)
print(’\t\tAufruf aus 2. Ebene: ’+var1E)
innereFktZweiterEbene()
187
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Innerhalb der Funktion innereFktErsterEbene wird hier die Variable varHauptpgm aufgerufen,
ebenso in der Funktion innereFktZweiterEbene. Das sieht so aus:
Diese wird in einer Datei [Link] gespeichert. In meinem neuen Programm will ich
diese Funktion benutzen. Zuerst kommt hier die erste der oben beschriebenen Arten des Aufrufs:
print([Link](13))
188
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
print(verdoppeln(13))
• etwas wird nur einmal geschrieben, und kann dann an verschiedenen Stellen, von verschiedenen
Programmen benutzt werden
• das Programm, an dem man gerade arbeitet, bleibt kurz und übersichtlich, weil der Code einer
Funktion nicht mehr in diesem Programm steht, sondern separat
Trotzdem kann es vorkommen, dass man an einer Funktion nachträglich etwas ändern muss, und dann
aber nicht alle Programme testen will, die diese Funktion benutzen. Da wäre es doch schön, wenn man
innerhalb der Datei, die die Funktion enthält, einen Test eingebaut hätte, der nur dann ausgeführt wird,
wenn diese Funktion getestet werden soll, aber nicht, wenn sie im produktiven Einsatz ist.
Natürlich gibt es diese Möglichkeit in Python. Das Mittel dazu ist die eingebaute Variable name .
So sieht das aus, wenn der Wert der Variablen name von der Python-Shell aus abgefragt wird:
diese Variable hat jetzt den Wert main . Als nächstes schreibe ich ein kleines Programm, das nur den
obigen Befehl enthält und speichere es unter dem Dateinamen [Link].
Erstaunlich!! Jetzt steht in der Variablen name der Name der importierten Datei! Das ist doch die
Lösung des Problems, einen Test einer Funktion nur durchzuführen, wenn wirklich getestet werden soll,
nämlich dann, wenn diese Funktion aus der Datei heraus, in der die Funktion steht, aufgerufen wird.
189
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
def irgendwas():
print(’irgendwas’)
if __name__ == ’__main__’:
irgendwas()
Über Gültigkeitsbereiche von Variablen ist bisher noch gar nichts gesagt worden, ganz einfach deswe-
gen, weil das bei der Konzeption von Python keine Bedeutung hatte. Oder wie es der Vater von Python
formuliert hat: We’re all consenting adults13“ Deswegen gilt: Variable sind immer überall gültig, sie
”
sind global. Das zeigen wir an einem Beispiel:
globaleVar = ’gloooobal!!’
def eineFunktion():
print(’in der ersten Funktion: ’+globaleVar)
Jetzt deklarieren wir eine zweite Funktion, innerhalb derer eine Variable mit dem selben Variablenna-
men definiert wird.
190
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Beispiel 7.5.35 Globale Variable und eine Funktion mit lokale Variablen
#!/usr/bin/python
# -*- coding: utf-8 -*-
globaleVar = ’gloooobal!!’
def eineFunktion():
print(’in der ersten Funktion: ’+globaleVar)
def zweiteFunktion():
globaleVar = ’aber eigentlich lokal!!’
print(globaleVar)
Das Ergebnis: die Variable globaleVar innerhalb der Funktion zweiteFunktion ist etwas ganz
anderes als die Variable außerhalb der Funktion. Dafür ist diese Variable aber nur innerhalb der zweiten
”
Funktion“ bekannt. Das bezeichnet man als lokale Variable“. Außerhalb dieser Funktion wird wieder
”
die globale Variable benutzt.
191
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Man kann dieses Verhalten verändern, indem man einer Variablen innerhalb einer Funktion das At-
tribut global“ zuordnet. Das sieht so aus:
”
Beispiel 7.5.37 Globale Variable und eine Funktion mit lokaler Variablen
#!/usr/bin/python
# -*- coding: utf-8 -*-
globaleVar = ’gloooobal!!’
def eineFunktion():
print(’in der ersten Funktion: ’+globaleVar)
def zweiteFunktion():
globaleVar = ’aber eigentlich lokal!!’
print(globaleVar)
def dritteFunktion():
global globaleVar
globaleVar = ’jetzt wieder global, weil in der 3. Fkt. "über-definiert"!!’
192
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
A CHTUNG
Eine rekursive Funktion ist eine Funktion, die in ihrem Funktionskörper sich selbst aufruft.
Es ist manchmal wirklich sinnvoll, von innerhalb einer Funktion dieselbe Funktion, eventuell mit ei-
nem anderen Wert für den Parameter, nochmals aufzurufen. Das wird als Rekursion“ bezeichnet. Eines
”
der klassischen Beispiele (oder vielleicht das Beispiel dazu überhaupt) ist die Berechnung der Fakultät
einer Zahl. Zur Erinnerung: 5! ist die mathematische Schreibweise für 5-Fakultät und ist definiert als 5!
=1*2*3*4*5
Oder anders gesagt: 5! = 5 * 4! und 4! = 4 * 3!. Das heißt, um 5! auszurechnen, wär es geschickt, wenn
man vorher 4! ausgerechnet hätte. Und so weiter, bis man bei der 1 angelangt ist.
193
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
In diesem Text sollen jetzt alle Zeilen, die Python“ enthalten, ausgegeben werden, wobei das Wort
”
Python“ in Großbuchstaben geschrieben werden soll.
”
Die dazugehörige Funktion, die das mit jeder einzelnen Zeile macht, ist schnell geschrieben. Gespei-
chert wird sie in der Datei [Link]
Auch der Rahmen für das zeilenweise Bearbeiten einer Textdatei ist kein Hexenwerk:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def textBearbeiten(????):
6 eingabeDatei = open(’[Link]’, ’r’)
7 wort = ’Python’
8 for eineZeile in [Link]():
9 if wort in eineZeile:
10 ????(eineZeile, wort)
11 [Link]()
12
13 if __name__ == ’__main__’:
14 textBearbeiten(????)
15
Auch wenn Dateien erst später im Text (siehe Kapitel 13 Dateizugriff“) behandelt werden, ist das
”
verständlich. Die beiden letzten Zeilen starten dieses Programm, falls es direkt aufgerufen wird und
nicht irgendwo importiert wird. Die Funktion textBearbeiten hat in der Parameterliste noch Fra-
gezeichen, denn noch weiß diese Funktion nicht, was sie überhaupt für eine Aufgaben bekommt. Als
erstes Aktion führt sie aber das Öffnen der Textdatei aus, das zu suchende Wort wird in der Variablen
wort abgelegt, und dann wird die gesamte Datei mittels readlines in eine Liste eingelesen. Diese
Liste wird in einer for“-Schleife abgearbeitet. Wenn das gesuchte Wort in einer Zeile auftaucht, dann
”
muss irgendwas mit dieser Zeile gemacht werden, aber da noch nicht klar ist, was, stehen hier auch
noch Fragezeichen.
Doch! Es ist doch klar, was mit jeder Zeile gemacht werden soll, nämlich das, was schon oben in
der Datei [Link] schon codiert wurde. Also muss ich doch nur noch ganz wenige Dinge
ändern.
1. die Funktion grossSchreiben muss aus der Datei [Link] importiert werden,
diesmal mit der Import-Option as eineFunktion“, damit die Funktion, die importiert wird, in-
”
nerhalb des Programms immer den selben Namen hat.
2. sie wird beim Aufruf von textBearbeiten mitgegeben
3. und im Kopf der Funktion textBearbeiten entgegengenommen
4. und dann aufgerufen, wenn das gesuchte Wort gefunden wurde.
194
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from grklSchreiben import grossSchreiben as eineFunktion
5
6 def textBearbeiten(eineFunktion):
7 eingabeDatei = open(’[Link]’, ’r’)
8 wort = ’Python’
9 for eineZeile in [Link]():
10 if wort in eineZeile:
11 eineFunktion(eineZeile, wort)
12 [Link]()
13
14 if __name__ == ’__main__’:
15 textBearbeiten(eineFunktion)
16
Das sieht umständlich aus? Es zahlt sich aber aus. Denn die Datei, die grossSchreiben enthält,
heißt ja [Link]. Schreib also dort eine weitere Funktion kleinSchreiben. Um diese
neue Funktion auf die Text-Datei loszulassen, muss nur eine Stelle in dem Programm geändert werden,
nämlich in der import“-Zeile! Wow!
”
[Link]. Seiteneffekte
7.5.10. lambda-Funktionen
lambda-Funktionen sind eigentlich lambda-Ausdrücke, aber sie arbeiten wie Funktionen. Sie werden
auch oft anonyme Funktionen“ genannt, denn diese Ausdrücke haben keinen Namen. Allerdings kann
”
ein lambda-Ausdruck einem Namen zugewiesen werden. Ein lambda-Ausdruck gibt immer einen Wert
zurück.
Die Syntax eines lambda-Ausdrucks besteht aus dem Schlüsselwort lambda, gefolgt von einer oder
mehreren Variablen, gefolgt von einem Doppelpunkt. Als letztes steht der Ausdruck, der etwas mit der
oder den Variablen macht. Als Beispiel soll hier eine Berechnung der nächsten Stundenzahl (12-Stunden-
Angaben) dienen; der Nachfolger von 6 ist 7, der Nachfolger von 12 ist aber 1.
195
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Dieser lambda-Ausdruck nimmt einen Wert für die Variable x entgegen, addiert 1 dazu und berechnet
den Rest modulo 12. Um diesen lambda-Ausdruck zu benutzen, muss er in Klammern geschrieben
werden, gefolgt von dem Wert des Parameters auch in Klammern.
Jetzt wird diesem Ausdruck ein Variablenname gegeben und dann aufgerufen.
Elegant sind lambda-Ausdrücke als Parameter für andere Funktionen. Ein Beispiel ist die Sortierung
einer Liste nach einem etwas ungewöhnlichen Sortierbegriff. Die Sortierung einer Liste erlaubt als Pa-
rameter das Schlüsselwort key, dem eine Funktion zugewiesen wird, die die Regel für die Sortierung
enthält. Hier soll eine Namensliste nach dem letzten Buchstaben des Namens sortiert werden.
196
KAPITEL 7. PROGRAMMSTRUKTUREN 7.5. FUNKTIONEN
Jetzt soll ein Dictionary sortiert werden, das als Schlüssel einen Vornamen hat, als Wert eine Liste
bestehend aus dem Nachnamen und dem Wohnort. Sortiert werden soll nach dem Wohnort.
Also wird zuerst aus den Dictionary-Keys und den Dictionary-Values eine Liste gezippt (denn Dic-
tionaries kennen keine Sortierung). Diese Liste wird mittels eines Lambda-Ausdrucks sortiert und dann
ausgegeben. Der lambda-Ausdruck holt aus der Liste das 1. Element (die Liste, die aus Nachname und
Wohnort besteht) und daraus das 1. Element (den Wohnort).
197
Teil V.
Programmentwicklung und
Modularisierung
199
8. Programmentwicklung mit Test
Da jetzt schon größere Programme geschrieben werden, vor allem, da jetzt auch Funktionen (Unter-
programme) eingebaut werden, ist es sinnvoll, dass der Entwickler sich schon beim Programmieren
Gedanken macht, was denn von einzelnen Funktionen erwartet wird. Auch da ist Python sehr hilfreich,
denn es kennt den doctest.
Der doctest funktioniert so, dass man in eine Funktion, direkt hinter den XrefId[?Funktionskopf?]
eine Zeichenkette in dreifachen Anführungszeichen schreibt. Diese Zeichenkette enthält in der ersten
Zeile nach 3 Größer-Zeichen einen möglichen Funktionsaufruf, darunter in der nächsten Zeile das er-
wartete Ergebnis.
Selbstverständlich kann man in diese Zeichenkette auch mehr als einen Test schreiben. Dann wieder-
holt sich wieder das Paar Zeile mit 3 Größer-Zeichen, gefolgt von einem möglichen Funktionsaufruf,
”
gefolgt von einer neuen Zeile mit dem erwarteten Ergebnis“.
Die Beschreibung, wie eine solche Funktion mit eingebautem Test aussieht, hört sich ziemlich umständlich
an. Ein Beispiel macht das aber hoffentlich klar. Es wird eine Funktion geschrieben, die bei 3 Zahlen (die
der Einfachheit halber der Größe nach aufsteigend eingegeben werden) überprüft, ob es sich um ein
pythagoräisches Zahlentripel handelt, ob also erste Zahl zum Quadrat plus zweite Zahl zum Quadrat
die dritte Zahl zum Quadrat ergibt.
Beispiel 8.1.1 Doctest (1. Versuch! Der tut noch nicht richtig!)
1
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def pythTripel(a,b,c):
6 """
7 >>> pythTripel(3,4,5)
8 True
9 >>> pythTripel(3,4,6)
10 False
11 """
12
13 import doctest
14 [Link]()
15
Hier wird also getestet, ob (3,4,5) ein pythagoräisches Zahlentripel ist, und bei diesem Test wird ein
True erwartet, dann wird (3,4,6) getestet, und bei diesem Test wird ein False erwartet. Das alles steht
innerhalb der Zeichenkette. Das Hauptprogramm importiert doctest und ruft danach den Test auf.
Die Ausgabe ist noch nicht ganz das, was wir im Endeffekt erwarten. Aber das ist ja klar, denn die
Funktion pythTripel macht noch nichts.
201
KAPITEL 8. PROGRAMMENTWICKLUNG . . . 8.1. DER DOCTEST
Beispiel 8.1.2 Ausgabe des Doctest (1. Versuch! Der tut noch nicht richtig!
1
2 **********************************************************************
3 File "/home/fmartin/bin/python/L14a_Doctest/[Link]",
4 line 6, in __main__.pythTripel
5 Failed example:
6 pythTripel(3,4,5)
7 Expected:
8 True
9 Got nothing
10 **********************************************************************
11 File "/home/fmartin/bin/python/L14a_Doctest/[Link]",
12 line 8, in __main__.pythTripel
13 Failed example:
14 pythTripel(3,4,6)
15 Expected:
16 False
17 Got nothing
18 **********************************************************************
19 1 items had failures:
20 2 of 2 in __main__.pythTripel
21 ***Test Failed*** 2 failures.
22
Man kann es wohl sofort verstehen, was da passiert. Bei beiden Tests steht ja da, was erwartet wird
(Expected:), und danach kommt das traurige Ergebnis, dass gar nichts passiert ist: Got nothing.
Das Fazit: 2 Tests wurden durchgeführt, beide gingen schief (***Test Failed*** 2 failures).
Wir wissen ja schon, woran es liegt: die Funktion tut noch gar nichts! Das können wir schnell ändern,
indem wir einfach von der Funktion zurückgeben lassen, ob a2 +b2 == c2 ist, also entweder den Wert
True oder den Wert False.
Beispiel 8.1.3 Doctest (2. Versuch! Jetzt sollte ein sinnvolles Ergebnis erscheinen)
1
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def pythTripel(a,b,c):
6 """
7 >>> pythTripel(3,4,5)
8 True
9 >>> pythTripel(3,4,6)
10 False
11 """
12 return a*a + b*b - c*c == 0
13
14 import doctest
15 [Link]()
16
Beispiel 8.1.4 Ausgabe des Doctest (Jetzt sollte ein sinnvolles Ergebnis erscheinen)
>>>
>>>
202
KAPITEL 8. PROGRAMMENTWICKLUNG . . . 8.1. DER DOCTEST
Die Ausgabe ist das absolute Nichts!!! Hm, was soll man damit anfangen? Ok, das ist zwar nicht das,
was sich der Programmieranfänger wünscht, aber es ist korrekt: es wird nichts ausgegeben, weil alle
Tests korrekt absolviert wurden.
Zum Glück gibt es aber noch einen Schalter, der auch in diesem Fall eine Ausgabe liefert, die uns
mehr Informationen bietet: verbose, also wörtlich (oder vielleicht eher geschwätzig).
Beispiel 8.1.5 Doctest (3. Versuch! Jetzt gibt es ein sinnvolles Ergebnis)
1
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def pythTripel(a,b,c):
6 """
7 >>> pythTripel(3,4,5)
8 True
9 >>> pythTripel(3,4,6)
10 False
11 """
12 return a*a + b*b - c*c == 0
13
14 import doctest
15 [Link](verbose=True)
16
Jetzt wird also ausdrücklich angegeben, was getestet wird, welches Ergebnis erwartet wird, und
zusätzlich die Information, dass der Test ok“ war.
”
203
KAPITEL 8. PROGRAMMENTWICKLUNG . . . 8.1. DER DOCTEST
204
9. Module und Pakete
Warum haben wir nicht das gesamten Mathematik-Modul hinzugeladen? Es gibt 2 wichtige Gründe:
erstens packt man so wenig in ein Programm hinein, wie möglich, so viel, wie nötig, zweitens verein-
facht man sich so die Benennung von Variablen, Konstanten, Funktionen usw. Schauen wir einmal, was
passiert, wenn man sich das ganze Mathematik-Modul hinzulädt:
205
KAPITEL 9. MODULE UND PAKETE 9.1. MEHR MATHEMATIK
Es scheint nichts geschehen zu sein. pi ist immer noch nicht bekannt, obwohl jetzt alles aus math“
”
in unser Programm importiert wurde. Aber wenn man ein ganzes Modul importiert, verbleiben alle
Variablen, Konstanten, Funktionen usw. im Namensraum des Moduls, das heißt, dass die Variablen
und Funktionen des Moduls nur als Teile des Moduls bekannt sind. Ich muss also die Variable pi durch
den vollständigen Namen ansprechen:
Vollständiger Name bedeutet, dass dem Konstantennamen pi hier der Modul-Name math vorange-
stellt wird, durch einen Punkt voneinander getrennt.
Bisher wurden 2 Methoden des Modul-Aufrufs angesprochen:
import modul
Es gibt noch eine dritte Methode, die hier erwähnt, vor der aber auch sehr gewarnt wird.
importiert alles aus dem Modul, aber alles wird in den Namensraum des aufrufenden Programms
übernommen. Das kann sehr gefährlich werden, wenn im aufrufenden Programm eine Variable oder
eine Funktion den selben Namen hat wie im Modul.
Im Modul math“ befindet sich natürlich noch viel mehr, aber was? Ganz einfach, fordern wir Hilfe
”
an:
206
KAPITEL 9. MODULE UND PAKETE 9.1. MEHR MATHEMATIK
NAME
math
FILE
/usr/lib/python2.5/lib-dynload/[Link]
MODULE DOCS
[Link]
DESCRIPTION
This module is always available. It provides access to the
mathematical functions defined by the C standard.
FUNCTIONS
acos(...)
acos(x)
asin(...)
asin(x)
atan(...)
atan(x)
atan2(...)
atan2(y, x)
ceil(...)
ceil(x)
cos(...)
cos(x)
Natürlich enden die mathematischen Funktionen hier nicht beim cos“! (Aber mehr muss in diesen
”
Text nicht rein, und wer mehr Mathematik braucht, weiß jetzt, wie man nachschlägt!) Aber damit kann
man doch schon ganz ordentlich arbeiten.
Das Inhaltsverzeichnis des Moduls math zeigt nicht so detailliert an, aber der Überblick ist hilfreich,
denn so weiß man, wonach man weiter blättern kann:
207
KAPITEL 9. MODULE UND PAKETE 9.2. EIGENE MODULE
1. Gehen wir davon aus, dass wir in einigen Dateien verschiedene kleine Funktionen geschrieben
haben, mit denen wir zufrieden sind, weil sie gut funktionieren. Also schieben wir diese Dateien
(oder besser vielleicht eine Kopie davon) in ein eigenes Verzeichnis, das wir der Einfachheit halber
eigeneModule“ nennen wollen.
”
2. Unsere erste Datei heißt [Link] und enthält zwei Funktionen, nämlich die Funktion fak,
die die Fakultät einer Zahl ausrechnet, und die Funktion binko, die den Binomialkoeffizienten
zweier Zahlen ausrechnet.
3. Unsere zweite Datei heißt [Link] und enthält eine Funktion fibo, die die n-te Fibonacci-Zahl
ausrechnet.
4. Jetzt erstelle ich eine Datei init .py, die aus den beiden vorher genannten Dateien die 3 Funk-
tionen importiert. Der Inhalt der Datei init .py ist also:
208
KAPITEL 9. MODULE UND PAKETE 9.2. EIGENE MODULE
5. Jetzt ist alles hergerichtet. Ich kann jetzt in einer anderen Datei das Modul aufrufen. Das sieht so
aus:
import eigeneModule
print([Link](5))
print([Link](5))
Wie man sieht, wird jetzt das ganze Modul importiert. Danach stehen die Funktionen unter
• [Link]()
• bzw. unter [Link]()
zur Verfügung.
Das soll jetzt noch ein wenig mehr Benutzerfreundlichkeit bekommen. Das eigene Modul soll auch
noch einen Hilfetext erhalten, den man sich bei Bedarf anschauen kann. Der Hilfetext ist einfach eine
Zeichenkette in dreifachen Anführungszeichen. Also sieht die Modul-Datei init .py so aus:
209
KAPITEL 9. MODULE UND PAKETE 9.3. PAKETE
Die Hilfe kann ich nach dem Import des Moduls aufrufen:
NAME
eigeneModule
FILE
/home/fmartin/bin/python/eigeneModule/__init__.py
DESCRIPTION
bisher voranden:
fak(z): berechnet die Fakultät von z
binko(n,k): berechnet n über k (Binomialkoeffizient)
fibo(z): berechnet die n-te Fibonacci-Zahl
PACKAGE CONTENTS
fakBinko
fibo
Dem, der unter Unix / Linux arbeitet, kommt diese Darstellung bekannt vor: so sehen alle Manuals3
aus. Das ist doch einfach schön, außerdem schön einfach und es freut den Lernenden, weil er etwas
wiedererkennt.
geschachtelte Struktur für Module muss noch geschrieben werden
9.3. Pakete
Ein Paket ist ein Verzeichnis, in dem verschiedene Module zusammengefasst sind. Damit Python das
als Paket erkennt, muss das Verzeichnis eine (eventuell leere) Datei init .py enthalten.
Wenn ich also ein Verzeichnis meinPaket anlege, das die Module SuperModul und SuperMario
enthält, binde ich einen dieser Module durch from meinPaket import SuperMario oder durch
import [Link] ein.
210
Teil VI.
Objektorientierte Programmierung
211
10. Klassen
10.1. Ist schon klasse, so eine Klasse!
Wie schon weiter oben bemerkt, ist Python eine objektorientierte Programmiersprache - nur hat das bis
hierher noch niemand gemerkt (oder fast kein Leser). Wenn wir bisher eine Variable deklariert haben,
dann dadurch, dass wir ihr einen Wert zugewiesen haben. Ohne uns darüber bewußt zu werden haben
wir aber dadurch gleichzeitig eine Zuordnung zu einer Klasse gemacht. Das ist einer der großen Vorteile
von Python: diese Sprache ist objektorientiert, aber man muss nicht objektorientiert programmieren, um
sie zu benutzen. Viele kleine Programme, zum Beispiel Werkzeuge, die man auf seinem eigenen Rechner
benutzt, schreibt ein geübter Programmierer in Python in ein paar Zeilen, ohne die Objektorientierung
auszupacken.
Was ist nun aber Objektorientierung? Und wozu dient sie?
Bei der objektorientierten Programmierung geht es darum, die für ein Programm relevanten Daten
möglichst naturgetreu“ abzubilden. Das Mittel dazu ist die Schaffung von Klassen, einer Beschreibung
”
von Eigenschaften gleichartiger Dinge. Diese gemeinsamen Eigenschaften werden in der Sprache der
Objektorientierung Attribute“ genannt. Diese gleichartigen Dinge haben aber nicht nur gemeinsame
”
Eigenschaften, sondern handeln“ auch gleich. Diese Handlungen von Elementen einer Klasse nennt
”
man Methoden“. Kurz gesagt:
”
• Attribute beschreiben Eigenschaften
• Methoden beschreiben Verhalten
Eine Klasse ist eine Vorlage für viele Objekte. In der Klasse wird beschrieben, wie jedes der zu erzeu-
genden Objekte aussehen soll und wie sich jedes der Objekte verhalten soll. Die Klasse selbst ist nur zu
dieser einen Sache zu gebrauchen: eines oder mehrere Objekte nach ihrem Muster zu bauen. Man kann
sich das vorstellen wie eine Ausstechform beim Plätzchenbacken. Die Form ist wirklich nicht geniess-
bar, weil sie aus Metall oder Plastik ist, aber was man damit aus dem Teig aussticht und backt: lecker,
lecker.
Damit kann man objektorientierte Programmierung so beschreiben: Attribute-Werte beschreiben den
Zustand eines Objekts, die Methoden verändern Attribute. Jedes Objekt behandelt die eigenen Daten
selbst und ist damit verantwortlich für seinen Zustand. Wie jedes Objekt diese Behandlung richtig
macht, weiß das Objekt, weil das Verhalten in der Klasse beschrieben ist.
Attribute und Methoden haben Namen. Man sollte sich von Anfang an darum bemühen, hier konse-
quente Schreibweisen einzuhalten. Wie für alle Variablennamen gilt auch für Attribute und Methoden,
dass sie klein geschrieben werden. Bei längeren Namen bietet sich die Schreibweise mit Unterstrich
(ein langer Variablen Name) oder die Kamel-Schreibweise (einLangerVariablenName) 1 an.
Die wichtigste Regel in Python für den Umgang mit Objekten und ihren Attribute und Methoden
folgt:
Viel wichtiger aber noch ist Konsequenz bei der Wahl des Namens. Wie aus dem vorvorigen Absatz
hervorgeht, beschreiben Attribute Eigenschaften. Für einen Attributnamen nimmt man also Substantive.
Die Werte der Attribute hingegen sind oft Adjektive: das Attribut Farbe“, als Attribut natürlich klein
”
farbe geschrieben, kann die Werte rot, grün, gelb etc. annehmen.
Methoden aber beschreiben, was mit dem Objekt passiert, meistens sogar genauer: was mit einem At-
tribut des Objekts passiert. Aus diesem Grund nimmt man für Methodennamen Verben, in Fortführung
des obigen Beispiels also etwa eine Methode farbeAendern.
Das Thema gute Programme“ (angefangen bei gute Programme) muss jetzt noch ergänzt werden.
”
Ein Programm ist gut, wenn eine Klassen-Definition gut ist. Das ist der Fall, wenn eine Klasse viele
1 .. die so heißt, weil die Großbuchstaben wie Kamelhöcker nach oben herausstehen.
213
KAPITEL 10. KLASSEN 10.1. IST SCHON KLASSE, SO EINE KLASSE!
kurze Methoden besitzt. Die Methodennamen sollten Verben sein, und ein Verb beschreibt genau eine
Tätigkeit. Eine Methode ist also gut geschrieben, wenn sie eine Aktion ausführt; das bedeutet andersher-
um aber auch, dass eine Klassenbeschreibung, bei der eine Methode mehr als eine Tätigkeit durchführt,
schlecht ist.
Wenn man sich an diese elementaren Regeln hält:
hat man für die objektorientierte Programmierung schon viel gewonnen und viele potentielle Feh-
lermöglichkeiten von vorneherein ausgeschaltet. Wenn man trotzdem irgendwann einen Namen hat,
der nicht diesen Regeln entspricht, hilft es oft, sich in ein Objekt der Klasse hineinzuversetzen. Ich
”
bin ein T-Shirt. Ich habe eine Farbe. Diese Farbe kann ich ändern.“ Das hört sich zwar am Anfang sehr
albern oder kindisch an, hilft aber, Strukturen zu erkennen.
Ein Beispiel für eine Klasse und die nach ihrem Muster erzeugten Objekte folgt hier: Stecker und
Steckdose sehen (in Deutschland) gleich aus und funktionieren gleich. Es reicht also, dass ich einmal all-
gemein beschreibe, wie Stecker und Steckdosen aussehen und was ihre Fähigkeiten sind. Dann benutze
ich diese Beschreibung, um einen Kühlschrank-Stecker, einen Computer-Stecker, einen Fön-Stecker zu
konstruieren. Wenn meine allgemeine Beschreibung fehlerfrei ist, dann bin ich sicher, dass alle speziel-
len Stecker fehlerfrei funktionieren.
Wenn man diese allgemeine Beschreibung macht — vorausgesetzt, man macht das sinnvoll und rich-
tig — erreicht man dadurch mehreres:
1. Es wächst zusammen, was zusammen gehört. (W. Brandt, aber in einem ganz anderen Zusam-
menhang!) Mit den Elementen einer Klasse kann man dann nicht mehr jeden Unfug anstellen,
sondern nur noch das, was in der Klasse als erlaubte Aktionen festgelegt wurde. Und man kann
einem Element einer Klasse auch keine Eigenschaften andichten, die nicht in der Klasse festgelegt
sind.
2. Und damit ist viel Code wiederverwertbar. Hat man erst einmal eine Klasse ordentlich beschrieben
und getestet, dann verhält die sich wie eine ganz nette schwarze Kiste: ich muss nicht mehr wissen,
was sich im Inneren der Kiste abspielt, sondern ich kann darauf vertrauen, dass sich ein Objekt,
das ich dieser Klasse zuordne, so verhält wie jedes andere Objekt dieser Klasse.
Vor allem ist Code damit wartbar geworden. Der Programmier-Anfänger hat oft die Vorstellung,
dass ein Programm einmal geschrieben und danach nie wieder angeschaut wird. Die Realität aber
ist, dass ein Programm geschrieben wird, die elementaren Eigenschaften, die gefordert wurden
abbildet, aber dass im Laufe der Zeit auffällt, dass z.B. Sonderfälle nicht behandelt wurden. Ebenso
merkt man erst im Laufe der Zeit, dass ein Programm, das von einem Benutzer interaktiv bedient
wird, nicht alle möglichen — damit sind vor allem die unmöglichen“ gemeint — Eingaben eines
”
Benutzers abfängt. Auch mit etwas, was ich als Programmierer gar nicht erwartet habe (soooo
doof kann doch kein Anwender sein), darf nicht dazu führen, dass etwas falsch bearbeitet wird
oder gar das Programm abbricht
Deswegen findet man oft verschiedene Versionen eines Programms, die sich dadurch unterschei-
den, dass mögliche Fehler ausgemerzt wurden — und andere dafür auftauchen. Deswegen ist es
wichtig, dass ein Programm nicht nur vom Programmierer zur Zeit des Programmierens verstan-
den wird, sondern auch noch Monate später und vielleicht von jemand ganz anderem gelesen
werden kann.
3. Von einer Klasse kann man andere Klassen herleiten. Das bedeutet, dass eine Klasse viele Eigen-
schaften einer anderen Klasse erben kann. Und schon wieder hat man Zeit und Arbeit gespart.
Lies noch einmal nach, was weiter oben über gute Programme geschrieben wurde, und Du verstehst,
dass Objektorientierung dazu beiträgt, Dinge einfach zu halten: einfach in der Bedeutung leicht“, aber
”
auch einfach in der Bedeutung nur einmal“.
”
In der Theorie der objektorientierten Programmierung haben sich im Laufe der Zeit Vorgehensweisen
und Richtlinien ergeben, die durch die folgenden Fachbegriffe im Zusammenhang mit objektorientierter
Programmierung beschrieben werden.
1. Vererbung: ein Stecker ist noch sehr allgemein; spezielle Stecker sind Kaltgerätestecker, Monitor-
Stecker, USB-Stecker. Alles, was prinzipiell Stecker auszeichnet, gilt für jeden dieser speziellen
Stecker; aber es gilt für jeden dieser Stecker noch ein bißchen mehr. Das heißt, dass jeder spezielle
214
KAPITEL 10. KLASSEN 10.1. IST SCHON KLASSE, SO EINE KLASSE!
Stecker die allgemeinen Eigenschaften vom allgemeinen Stecker erbt und noch ein paar spezielle
Eigenschaften hinzugefügt werden.
2. Kapselung: alles, was zu einer Klasse gehört, soll (oder manchmal: kann) nur von Objekten dieser
Klasse angesprochen werden. Von außen sind die Eigenschaften der Klasse versteckt“, und damit
”
gerät man weniger in Gefahr, mit Variablen irgendeinen Unsinn zu machen.
3. Polymorphie heißt Vielgestaltigkeit“. Damit ist gemeint, dass sich eine Eigenschaft in verschie-
”
denen Klassen verschieden zeigen kann. Ein ganz einfaches Beispiel haben wir schon weiter oben
kennen gelernt, nur ist das gar nicht richtig aufgefallen. Das Zeichen + bezeichnet eine Eigen-
schaft von Zahlen, aber auch eine von Zeichenketten. In Verbindung mit Zahlen bedeutet es die
aus der Schule gewohnte Addition; in Verbindung mit Zeichenketten bedeutet es das Hinterein-
anderschreiben.
Die erste Klasse erstellen wir in IDLE. Das erlaubt es uns, wirklich interaktiv mit der Klasse her-
umzuspielen. Außerdem ist der Editor von IDLE da sehr hilfreich, wie man gleich sehen wird. Eine
Klasse wird durch das Schlüsselwort class festgelegt. Als nächstes benötigt eine Klasse einen Namen.
Während es in der Umgangssprache die Klasse der Autos“ heißt, ist es in der (Python-)Programmierung
”
üblich, dass der Name einer Klasse ein Substantiv im Singular ist. Hier darf zum ersten Mal ein Groß-
buchstabe am Anfang eines Namens verwendet werden: Klassennamen beginnen mit einem Groß-
buchstaben. Die erste Klasse ist eine Erweiterung des Grusses, den man am Anfang jeder Program-
miertätigkeit an die Welt schicken sollte, das Hallo, Welt“. Jetzt wird es aber in der Form aufgebohrt,
”
dass eine Person einen Vornamen hat (das soll das einzige Attribut der Person sein) und die Welt höflich
grüßen kann, indem sie auch den eigenen Namen nennt (das wird die einzige Methode der Person).
2 class Person:
3 def __init__(self, vorname):
4 [Link] = vorname
5
6 def gruessen(self):
7 print(’Ein freundliches "Hallo Welt" von ’+[Link]=
8
2 Genau genommen ist das kein Konstruktor. Wer dazu mehr wissen will, sollte die Dokumentation zu Python nachlesen. Aber
die hier beschriebene Methode kommt einem Konstruktor sehr nahe. Also belassen wir es bei dieser Bezeichnung.
3 self entspricht dem this in den Sprachen C und Java. Anders als in diesen Sprachen ist aber self kein reserviertes Wort in
Python. Das bedeutet, dass man durchaus einen anderen Namen dafür benutzen könnte. Aber das sollte man auf keinen Fall
machen. self ist zwar nur eine Empfehlung, aber eine sehr massive!!
Also eher: Du willst doch nicht etwa statt self etwas anderes nehmen??!!!??!!!
215
KAPITEL 10. KLASSEN 10.1. IST SCHON KLASSE, SO EINE KLASSE!
Ja, auch mir tut das weh, dass da als Anweisung [Link]()“ steht, [Link]()“ wäre schöner.
” ”
Aber auch hier gilt eine Vereinbarung: so wie Klassennamen immer ein Substantiv im Nominativ sin-
gular sein sollen, sollen Methodennamen immer ein Verb im Infinitiv sein. Zuerst wird eine Person ich
angelegt. Die benötigt als Attribut einen Vornamen, und der wird als Parameter beim Aufruf der Klas-
se Person mitgegeben. Innerhalb des Konstruktors init wird der Wert dieses Parameters an die
Instanz übergeben, die für das jeweilige Objekt immer mit self angesprochen wird. Die einzige Me-
thode der Klasse wird auch an jedes Objekt weitergegeben, so dass jetzt ich es beherrscht, die Welt zu
gruessen. Das geschieht dadurch, dass der Methodenname durch einen Punkt an den Objektnamen
angehängt wird.
Das zweite Beispiel soll ein bißchen mehr sein und können (sein: das sind die Attribute; können: das
sind die Methoden) Bauen wir also die Klasse Angestellter, die als Attribute den Namen, das Alter,
das Einkommen und die Berufsbezeichnung hat.
Und nochmal: die Klasse macht nichts, ist nichts ... außer einem Muster. Objekte nach dem Muster
werden erstellt durch
216
KAPITEL 10. KLASSEN 10.1. IST SCHON KLASSE, SO EINE KLASSE!
Aber die 3 Objekte verhalten sich jetzt so, wie es in der Klassenbeschreibung (im Muster) vorgegeben
wurde.
Der Konstruktor einer Klasse heißt in Python immer init . (Das sind zwei Unterstriche vor dem
init und zwei nach dem init.) Wenn ich jetzt also ein Objekt der Klasse Angestellter erzeugen will,
stelle ich eine Variable bereit, in diesem Fall die Variable ich, der ich mitteile, dass sie einen Angestell-
ten darstellen soll. In Klammern werden die Attribute angegeben, also Name, Alter, Einkommen und
Berufsbezeichnung. Damit wird jetzt der Konstruktor der Klasse aufgerufen. Der Konstruktor hat in
Klammern ebenfalls die Attribute angegeben, damit er das, was übergeben wird, in Empfang nimmt.
Zusätzlich hat der Konstruktor immer als ersten Parameter den Parameter self, der eine Referenz auf
sich selbst ist, in diesem Fall also auf die Variable ich. Jetzt werden die übergebenen Parameterwerte
an Attribute des Objekts weitergegeben, was durch die Anweisung [Link] = name geschieht. Da-
mit wird jetzt dem Attribut name des Objekts ich der Wert Martin Schimmels“ zugeordnet. Dass das
”
tatsächlich funktioniert hat, sieht man einige Zeilen später, wenn der Wert von [Link] ausgegeben
wird. Der ist tatsächlich vorhanden und lautet Martin Schimmels“.
”
Objektorientierung geht heute - im ersten Jahrzehnt des 21. Jahrhunderts - nicht mehr ohne UML.
UML ist die Abkürzung für Unified Modelling Language“. Und genau das ist es: eine vereinheitliche
”
Modellierungssprache für die Modellierung von Klassen (und anderem mehr. Aber das gehört jetzt
nicht hierher!).
Modellieren wir also unsere zweite Klasse: Menschen!! (Aber abstrahieren wir soviel es geht, damit
unser Modell einer Klasse überschaubar bleibt.) Menschen haben einen Vornamen, einen Nachnamen,
ein Geburtsdatum. Geburtsdatum und Vorname sind unveränderlich (wenn man mal von Künstlern
und Verbrechern absieht), der Nachname kann sich ändern. Menschen haben einen Wohnort, und der
ändert sich (wahrscheinlich häufiger als der Nachname). So! Das reicht!
In UML sieht das Modell der Klasse Mensch, wie es oben beschrieben wurde, so aus:
So schön kann ich natürlich nicht von Hand zeichnen. Es gibt zum Glück jede Menge UML-Programme,
die eine Klasse modellieren und das Ergebnis schön darstellen. Das oben stehende Diagramm wurde
mit dem Programm Umbrello“ gezeichnet, das aus der Linux-Ecke kommt und Open Source“ ist, also
” ”
nichts kostet.
Eine kurze Beschreibung dessen, was man da sieht: im oberen kleinen Kasten steht der Name der
Klasse. Vereinbarung: Klassennamen beginnen mit einem Großbuchstaben. Im zweiten Kasten stehen
die Eigenschaften, in UML Attribute genannt, die durch ein vorangestelltes Minus-Zeichen markiert
sind.
In unserem Fall sind die 3 Attribute allesamt Zeichenketten, auf englisch strings“. Im dritten Kas-
”
ten stehen die Aktionen, in UML Methoden genannt, gekennzeichnet durch ein vorangestelltes Plus-
Zeichen. Hier ist Umbrello in Aktion, das nicht für eine bestimmte Programmiersprache entworfen wur-
de, sondern für viele Programmiersprachen einsetzbar ist. In fast allen anderen Programmiersprachen
muss man bei der Deklaration einer Variablen angeben, welchen Typ diese Variable zum Inhalt haben
soll, etwa, dass die Variable vom Typ int“ (für integer, also ganze Zahlen) oder vom Typ string“ (für
” ”
217
KAPITEL 10. KLASSEN 10.2. OBJEKTE, OBJEKTE, OBJEKTE
Zeichenketten) sein soll. In Python ist das anders: durch die erste Zuweisung eines Wertes an eine Va-
riable wird die Klasse festgelegt, zu der die Variable gehört. In unserem Fall muss man den Methoden
jeweils eine Information mitgeben: der Methode nachnamenAendern den neuen Nachnamen, der Me-
thode umziehen den neuen Wohnort. Das, was einer Methode mitgegeben wird, wird als Parameter
der Methode bezeichnet.
Methoden sind im Prinzip nicht viel anders als Funktionen, mit dem Unterschied, dass sie an eine
Klasse gebunden sind und nur von Objekten der Klasse benutzt werden können. Das kommt Dir wohl
schon bekannt vor, denn oben haben wir den Begriff des Namensraums eingeführt. Damit kann dieser
Sachverhalt auch anders beschrieben werden: der Namensraum einer Methode ist die Klasse. Ebenso
gilt, dass ein Attribut eine Variable ist, die als Namensraum die Klasse hat.
Eigentlich sollte es überflüssig sein, das nochmals zu erwähnen, aber trotzdem: Attribute sind Varia-
blen, Methoden sind Funktionen, also beginnen Attribut- und Methodennamen mit einem Kleinbuch-
staben.
Eine Klasse wird definiert durch das Schlüsselwort class, gefolgt vom Klassennamen, gefolgt von
einem Paar runder Klammern, in denen eventuell Parameter dieser Klasse stehen. Unsere Klasse be-
kommt im ersten Schritt nur einen Konstruktor. Der Konstruktor wird bei uns mit 5 Parametern aufge-
rufen: der erste Parameter, self, ist Pflicht!!!!! Danach folgen die Parameter, in denen die Werte für jedes
Attribut, das wir deklariert haben, dem Konstruktor mitgegeben werden. In den folgenden Zeilen wird
dem Attribut, gekennzeichnet durch das vorangestellte self, der jeweilige Parameter zugewiesen. An
einem Beispiel verdeutlicht: der Parameter vorname aus der runden Klammer hinter dem Konstruktor-
Namen init wird dem Attribut der Klasse, dem [Link] zugewiesen.
Man sieht: Methoden sehen fast aus wie Funktionen. Es sind auch Funktionen, die aber nicht von
überall gesehen werden und von überall benutzt werden dürfen. Es sind Funktionen, die an Klassen
bzw. an Objekte dieser Klassen gebunden sind.
Die wichtigste Regel im Umgang mit Klassen in Python wiederhole ich also nochmals:
• alles, was zu einer Klasse gehört, egal ob Attribut oder Methode, wird geschrieben als
– [Link]
– bzw. [Link]
Klassenname und Attribut bzw. Klassenname und Methode werden durch einen Punkt voneinan-
der getrennt. Das Schlüsselwort self verweist immer auf das aktuelle Objekt der Klasse, oft auch
die Instanz der Klasse“ genannt.
”
4 Es ist eine gute Sache, sich anzugewöhnen, Klassen-Dateien immer mit cl“ (oder cl “ oder kl“ oder so ähnlich) anfangen
” ” ”
zu lassen. Sollte man später beruflich in einem Unternehmen programmieren dürfen, wird es sowieso Vorgaben geben, wie
Dateien zu benennen sind.
218
KAPITEL 10. KLASSEN 10.2. OBJEKTE, OBJEKTE, OBJEKTE
Zum Test benötigen wir dann noch eine zweite Datei, [Link], in der wir ein Objekt der
Klasse erzeugen.
Zuerst muss das Aufruf-Programm natürlich die Klasse importieren. Erst dann kann man ein Objekt
konstruieren. Dazu vergebe ich einen Variablennamen und teile dem Programm mit, dass die Variable
jetzt ein Platzhalter für ein Objekt der Klasse Mensch ist. Das geschieht durch den Zuweisungsoperator
=. Dadurch wird der Konstruktor der Klasse aufgerufen, und der benötigt eine ganze Menge Parameter.
Der Parameter self muss nicht übergeben werden, aber die anderen vier: Vorname, Nachname, Ge-
burtsdatum und Wohnort. So! Objekt erzeugt!!! (Und wenn ich das Programm jetzt laufen lasse, tut sich
gar nichts.)
Also wird unser aufrufendes Programm in einem zweiten Schritt erweitert:
So! Jetzt tut sich etwas: Vor- und Nachname werden angezeigt.
Das, was ich im oben stehenden Beispiel gemacht habe, ist eigentlich absolut verboten: ausserhalb
der Klassen-Definition soll man nicht auf Attribute zugreifen. (Siehe dazu weiter unten bei XrefId[??]
Sichtbarkeit.) Für den Zugriff auf Attribute soll man immer eigene Methoden schreiben. Hier (und das
wiederholt sich für viele unserer Beispiele) schreiben wir also einfach eine Methode, die alle Attribute
eines Objektes und damit das ganze Objekt anzeigt. Damit ändert sich unsere Klassendatei so:
def anzeigen(self):
print([Link]+’ ’+[Link])
print([Link])
print([Link])
Die Regel von oben wurde auf jeden Fall eingehalten: Die Methode anzeigen führt genau eine Auf-
gabe aus (nämlich die, die durch den Methoden-Namen vorgegeben ist). Also muss dazu nicht mehr
gesagt werden. Nach der Erzeugung eines Objektes greife ich jetzt also nicht mehr auf die Attribute des
Objektes zu, sondern auf eine Methode!
219
KAPITEL 10. KLASSEN 10.2. OBJEKTE, OBJEKTE, OBJEKTE
Wie angekündigt, Schritt für Schritt, wird das Programm unserem Modell angepasst. Die Klasse
braucht eine Methode nachnamenAendern.
def anzeigen(self):
print([Link]+’ ’+[Link])
print([Link])
print([Link])
220
KAPITEL 10. KLASSEN 10.3. KAPSELUNG
2 class Mensch():
3 def __init__(self, vorname, nachname, gebdat, wohnort):
4 [Link] = vorname
5 [Link] = nachname
6 [Link] = gebdat
7 [Link] = wohnort
8
9 def anzeigen(self):
10 print([Link]+’ ’+[Link])
11 print([Link])
12 print([Link])
13
2 #!/usr/bin/python
3 from clMensch import Mensch
4
10 [Link](’Ammerbuch’)
11 [Link]()
12
10.3. Kapselung
Die bisherigen Beispiele haben aus Sicht der Objektorientierung noch einen gewaltigen Fehler. Auf At-
tribute kann man beim obigen Beispiel von außerhalb der Klasse zugreifen, das heißt, dass in einem
Programm folgendes möglich ist:
2 #!/usr/bin/python
3 from clMensch import Mensch
4
Auf Attribute sollte nur mittels Methoden der Klasse zugegriffen werden. Python hat hier eine Schwäche,
denn anders als in anderen objektorientierten Sprachen wird bei der Deklaration einer Variablen weder
ein Datentyp noch eine Sichtbarkeitsklausel angegeben.
221
KAPITEL 10. KLASSEN 10.3. KAPSELUNG
1. public: Jeder darf von überall alles mit dem Attribut machen.
2. protected: nur die eigene Klasse und daraus abgeleitete Klassen dürfen auf ein solches Attribut
zugreifen.
3. private: Die stärkste Sicherheit: hier darf nur die eigene Klasse auf das Attribut zugreifen.
In Python wird die Sichtbarkeitsstufe durch vorangestellte Unterstriche dargestellt. Das ist leider keine
absolute Sicherheit gegen einen missbräuchlichen Zugriff auf ein Attribut. Die Regeln in Python lauten:
1. Ein Attribut ohne einen führenden Unterstrich ist public, also auch von außerhalb der Klasse les-
bar und veränderbar.
2. Ein Attribut mit genau einem führenden Unterstrich ist protected; damit ist noch keine Sicherheit
gegeben, aber der Programmierer tut damit kund, dass man auf dieses Attribut nicht von außer-
halb zugreifen sollte.
3. Ein Attribut mit genau zwei führenden Unterstrichen ist private; dieses Attribut ist von außerhalb
der Klasse nicht sichtbar und kann somit nur durch Methoden der Klasse gelesen und geschrieben
werden.
Also sollte man dieses Progrämmchen noch richtig machen (richtig im Sinne der Objektorientierung).
Die Attribute werden privat“ gemacht, so dass nur noch über die Methoden zugegriffen werden kann.
”
2 class Mensch():
3 def __init__(self, vorname, nachname, gebdat, wohnort):
4 self.__vorname = vorname
5 self.__nachname = nachname
6 self.__gebdat = gebdat
7 self.__wohnort = wohnort
8
9 def anzeigen(self):
10 print(self.__vorname+’ ’+self.__nachname)
11 print(self.__gebdat)
12 print(self.__wohnort)
13
Die 3 Attribute vorname, nachname und wohnort haben im Konstruktor zwei Unterstriche voran-
gestellt. In der Methode anzeigen und den beiden Methoden, die Wohnort und Nachname ändern,
müssen natürlich dann auch die Attribute mit vorangestelltem Unterstrich angesprochen werden.
Das aufrufende Programm ändert sich gar nicht — außer, dass in der Zeile nach dem ersten Anzeigen
ein Fehler eingebaut wird: es wird nämlich der Versuch gemacht, auf das Attribut nachname von
außerhalb der Klasse zuzugreifen.
222
KAPITEL 10. KLASSEN 10.4. SETTER UND GETTER? ODER DOCH . . .
2 #!/usr/bin/python
3 from clMensch import Mensch
4
11 [Link](’Meier’)
12 [Link]()
13
14 [Link](’Ammerbuch’)
15 [Link]()
16
223
KAPITEL 10. KLASSEN 10.4. SETTER UND GETTER? ODER DOCH . . .
Zuerst einmal schreibe ich die Methoden und rufe eine davon direkt auf.
3 class Hund():
4 def __init__(self, rasse, name):
5 self.set_rasse(rasse)
6 self.set_name(name)
7
8 def get_rasse(self):
9 return [Link]
10
14 def get_name(self):
15 return [Link]
16
20
21 if __name__ == ’__main__’:
22 w = Hund(’Dackel’, ’Waldi’)
23 h = Hund(’Schäferhund’, ’Hasso’)
24 print(w.get_name())
25 print(h.get_name())
26
27
3 Waldi
4 Hasso
5
Python-Programmierer machen das aber mit Eigenschaften, das heißt über das Schlüsselwort property
werden den jeweiligen Attributen Methoden zugeordnet.
224
KAPITEL 10. KLASSEN 10.4. SETTER UND GETTER? ODER DOCH . . .
3 #!/usr/bin/python
4
5 class Hund():
6 def __init__(self, rasse, name):
7 self.unsichtbare_rasse = rasse
8 self.unsichtbarer_name = name
9
10 def get_rasse(self):
11 return self.unsichtbare_rasse
12
16 def get_name(self):
17 return self.unsichtbarer_name
18
25 if __name__ == ’__main__’:
26 w = Hund(’Dackel’, ’Waldi’)
27 h = Hund(’Schäferhund’, ’Hasso’)
28 print([Link])
29 print([Link])
30 [Link] = ’Titan’
31 print(’Hasso heißt jetzt ’+[Link])
32
33
Wird jetzt einem Attribut ein Wert zugewiesen, wird der Setter des Attributs aufgerufen; der Getter
wird aufgerufen, wenn der Name des Attributs abgefragt wird. Das liefert die erwartete Ausgabe:
Beispiel 10.4.4 Ausgabe von Getter und Setter mit Hilfe von property
1
3 Waldi
4 Hasso
5 Hasso heißt jetzt Titan
6
Das ist jetzt besonders wichtig, wenn wir uns wieder der Sichtbarkeit von Attributen zuwenden.
Erinnerst Du Dich noch? Sonst lies noch mal nach! Hier kommt also die obige Klasse, nur mit der
Veränderung, dass jetzt beide Attribute durch vorangestellte doppelte Unterstriche privat geworden
sind.
225
KAPITEL 10. KLASSEN 10.4. SETTER UND GETTER? ODER DOCH . . .
Beispiel 10.4.5 Getter und Setter mit Hilfe von property und private Attribute
1
3 #!/usr/bin/python
4
5 class Hund():
6 def __init__(self, rasse, name):
7 self.__unsichtbare_rasse = rasse
8 self.__unsichtbarer_name = name
9
10 def get_rasse(self):
11 return self.__unsichtbare_rasse
12
16 def get_name(self):
17 return self.__unsichtbarer_name
18
25 if __name__ == ’__main__’:
26 w = Hund(’Dackel’, ’Waldi’)
27 h = Hund(’Schäferhund’, ’Hasso’)
28 print([Link])
29 print([Link])
30 [Link] = ’Titan’
31 print(’Hasso heißt jetzt ’+[Link])
32 print(’Das nächste funktioniert nicht,
33 \ndenn "__unsichtbarer_name" ist wirklich unsichtbar’)
34 print(’Hasso heißt jetzt ’+h.__unsichtbarer_name)
35
36
Beispiel 10.4.6 Ausgabe mit Hilfe von property und privaten Attributen
1
3 Waldi
4 Hasso
5 Hasso heißt jetzt Titan
6 Das nächste funktioniert nicht,
7 denn "__unsichtbarer_name" ist wirklich unsichtbar
8 Traceback (most recent call last):
9 File "./cl_HundPropertySichtbarkeit.py", line 33, in <module>
10 print(’Hasso heißt jetzt ’+h.__unsichtbarer_name)
11 AttributeError: ’Hund’ object has no attribute ’__unsichtbarer_name’
12
13
226
KAPITEL 10. KLASSEN 10.5. STATISCHE METHODEN
14
15 >>> [Link]()
16 jeder Mensch wohnt irgendwo
17 >>> x = Mensch(’Martin’, ’Schimmels’)
18 >>> [Link]()
19 Martin Schimmels
20 jeder Mensch wohnt irgendwo
21 >>>
22
23
In Zeile 6 wird die Methode wohnen zu einer statischen Methode gemacht. In Zeile 15 sieht man,
dass der Aufruf der Methode als Methode der Klasse funktioniert. Nachdem in Zeile 17 ein Objekt der
Klasse erzeugt wurde, wird in der darauffolgenden Zeile die Methode wohnen des Objekts aufgerufen,
und auch das funktioniert.
227
KAPITEL 10. KLASSEN 10.6. VERERBUNG (OHNE . . .
Die oben angegebene Schreibweise ist anschaulich und verständlich. Mittels Dekoratoren“ kann die
”
Schreibweise verkürzt werden:
13 >>> [Link]()
14 jeder Mensch wohnt irgendwo
15 >>> x = Mensch(’Hannah’, ’Schimmels’)
16 >>> [Link]()
17 Hannah Schimmels
18 jeder Mensch wohnt irgendwo
19
228
KAPITEL 10. KLASSEN 10.6. VERERBUNG (OHNE . . .
Hier werden 3 Klassen abgebildet, und diese Klassen sind durch Pfeile miteinander verbunden. Der
Pfeil zeigt immer auf die übergeordnete Klasse, von der die untergeordneten Klassen etwas (in diesem
Beispiel: alles!) erben. Umbrello spricht hier von einer gerichteten Assoziation“. Die Eigenschaften, die
”
die untergeordneten (in UML: abgeleiteten) Klassen erben, müssen dort nicht mehr aufgeführt werden.
Alles Gute kommt von oben!
Die Realisierung in Python sieht so aus:
2 class Mensch():
3 def __init__(self, vorname, nachname, gebdat, wohnort):
4 [Link] = vorname
5 [Link] = nachname
6 [Link] = gebdat
7 [Link] = wohnort
8
9 def anzeigen(self):
10 print([Link]+’ ’+[Link])
11 print([Link])
12 print([Link])
13
20 class Schueler(Mensch):
21 def __init__(self, vorname, nachname, gebdat, wohnort, klasse):
22 Mensch.__init__(self, vorname, nachname, gebdat, wohnort)
23 [Link] = klasse
24
25 def versetzen(self):
26 [Link] += 1
27
Auch hier gibt es eine kurze Erläuterung: in die selbe Datei wie die Klasse Mensch schreibe ich die
Klasse Schueler (keine Umlaute!!!). Um Python anzuweisen, dass es Schueler als eine Unterklasse von
229
KAPITEL 10. KLASSEN 10.6. VERERBUNG (OHNE . . .
Mensch auffassen soll, wird dem Klassennamen in Klammern die Bezeichnung der Oberklasse mitge-
teilt. Der Konstruktor nimmt wieder alle Attribute in Empfang, aber reicht gleich die Attribute, die die
Klasse Schueler von der Klasse Mensch erbt, weiter an den Konstruktor von Mensch nach dem Mot-
to: Mach Du das doch, Du weißt doch schon, wie das geht.“ Das geschieht durch den ausdrücklichen
”
Aufruf des Konstruktors der Oberklasse: Mensch. init (...). Einzig die (Schul-)Klasse muss hier
in der Unterklasse Schueler initialisiert werden.
Die neue Methode ist wohl ganz leicht zu verstehen. Es wird der Kurzschluß-Operator für die Addi-
tion benutzt.
Jetzt brauchen wir wieder ein Aufruf-Programm, mit dem man die neue Klassen-Definition testen
kann. Hier müssen zwei Klassen-Definitionen importiert werden, die durch Komma voneinander ge-
trennt werden:
2 #!/usr/bin/python
3 from clMensch import Mensch, Schueler
4
7 [Link]()
8 [Link](’Meier’)
9 [Link]()
10 ###
11 # ab hier gibt es was neues
12 ###
13 thomas = Schueler(’Thomas’, ’Renz’, ’12.11.1989’, ’Dettenhausen’, 11)
14
15 [Link]()
16
17 [Link]()
18 [Link]()
19
230
KAPITEL 10. KLASSEN 10.6. VERERBUNG (OHNE . . .
2 class Ebene1(object):
3 def anzeigen(self):
4 print(’das ist Ebene 1, die Grosseltern-Ebene’)
5
6 class Ebene2(Ebene1):
7 def anzeigen(self):
8 print(’das ist Ebene 2, die Eltern-Ebene’)
9
10 class Ebene3(Ebene2):
11 def anzeigen(self):
12 print(’das ist Ebene 3’)
13 print(’aber ich kenne auch meine Eltern und Grosseltern’)
14 super(Ebene3, self).anzeigen()
15 super(Ebene2, self).anzeigen()
16
Die Methode anzeigen der Klasse Ebene3 kann einfacher geschrieben werden, da an der Stelle des
Aufrufs klar ist, was die super“-Ebene ist:
”
Beispiel 10.6.4 Vereinfachte Methode bei eindeutiger Superklasse
1
2 class Ebene3(Ebene2):
3 def anzeigen(self):
4 print(’das ist Ebene 3’)
5 print(’aber ich kenne auch meine Eltern und Grosseltern. SCHAUT!!!’)
6 super().anzeigen()
7 super(Ebene2, self).anzeigen()
8
231
KAPITEL 10. KLASSEN 10.6. VERERBUNG (OHNE . . .
2 class Mensch(object):
3 def __init__(self, vorname, nachname, gebdat, wohnort):
4 [Link] = vorname
5 [Link] = nachname
6 [Link] = gebdat
7 [Link] = wohnort
8
9 def anzeigen(self):
10 print([Link]+’ ’+[Link])
11 print([Link])
12 print([Link])
13
In Bezug auf Vererbung ändert sich auch etwas: der Aufruf der Methoden der Oberklasse soll nicht
mehr durch das Voranstellen des Oberklassen-Namens geschehen, sondern durch die Benutzung der
Funktion super. super bekommt immer 2 Parameter: der erste Parameter ist der Name der (aktuellen)
Unterklasse, der zweite Parameter ein Verweis auf das aktuelle Objekt, also self. Das hört sich kom-
pliziert an, vereinfacht aber das Vorgehen wieder erheblich; es bedeutet nämlich umgangssprachlich
formuliert wieder Hey, Objekt, Du weißt doch, von was Du erbst, also ruf mal das oder das von Deiner
”
Oberklasse auf“. Die Intelligenz steckt also wieder in der Klasse.
Aus dem vorigen Kapitel wird hier der Aufruf des Konstruktors der Oberklasse neu formuliert.
Zusätzlich bekommt die Unterklasse aber eine Methode anzeigen, um zu demonstrieren, dass auch
eine beliebige Methode mit Hilfe von super aufgerufen werden kann. Das Beispiel aus dem vorigen
Kapitel mit der abgeleiteten Klasse Schueler verändert sich zu:
232
KAPITEL 10. KLASSEN 10.7. METHODEN ÜBERSCHREIBEN
2 class Mensch():
3 def __init__(self, vorname, nachname, gebdat, wohnort):
4 [Link] = vorname
5 [Link] = nachname
6 [Link] = gebdat
7 [Link] = wohnort
8
9 def anzeigen(self):
10 print([Link]+’ ’+[Link])
11 print([Link])
12 print([Link])
13
20 class Schueler(Mensch):
21 def __init__(self, vorname, nachname, gebdat, wohnort, klasse):
22 super(Schueler, self).__init__(vorname, nachname, gebdat, wohnort)
23 [Link] = klasse
24
25 def versetzen(self):
26 [Link] += 1
27
28 def anzeigen(self):
29 super(Schueler, self).anzeigen()
30 print(’in Klasse:’, [Link])
31
• Der Schüler benötigt noch eine Methode anzeigen. Dabei sollte selbstverständlich die Methode
anzeigen von Mensch benutzt werden, so weit das möglich ist.
• Die Klasse Lehrer muss noch geschrieben werden.
233
KAPITEL 10. KLASSEN 10.7. METHODEN ÜBERSCHREIBEN
2 #!/usr/bin/python
3
4 class Person():
5 def __init__(self, name, anrede):
6 [Link] = name
7 [Link] = anrede
8 def namenAusgeben(self):
9 return [Link]
10 def anreden(self):
11 return [Link] +’, ’+[Link]
12
13 class Herr(Person):
14 def anreden(self):
15 return [Link]+’, Herr ’+[Link]
16
17
18 class Frau(Person):
19 def anreden(self):
20 return [Link]+’, Frau ’+[Link]
21
2 Hi hello, Martin
3 Einen wunderschönen guten Tag, Frau Schreiner
4 Guten Tag, Herr Maler
5
Jede der 3 Klassen hat eine Methode anzeigen. Die Methode einer der beiden spezialisierten Klassen
Herr bzw. Frau überschreiben die allgemeinere Version. Das bedeutet, dass die speziellere Version von
anzeigen benutzt wird, wenn ein Objekt der spezielleren Klasse angelegt wird und diese Methode
aufgerufen wird.
2 >>> 3+4
3 7
4
234
KAPITEL 10. KLASSEN 10.7. METHODEN ÜBERSCHREIBEN
Aber rationale Zahlen werden ja (oft, sinnvollerweise) als Brüche geschrieben. Da ist der Algorithmus
für die Addition ja nicht der selbe wie bei der Addition von natürlichen oder ganzen Zahlen:
1. größten gemeinsamen Teiler der beiden Nenner suchen; das ist der Hauptnenner
2. beide Brüche durch eventuelles Erweitern auf den Hauptnenner bringen
3. die beiden Zähler addieren
Das kann auch in einer anderen Reihenfolge gemacht werden, und das ist für die Programmierung
etwas einfacher.
1. Zähler des ersten Bruchs mit dem Nenner des zweiten Bruchs multiplizieren, dazu das Produkt
von Zähler des zweiten Bruchs mit Nenner des ersten Bruchs addieren
2. dieses Produkt ist der neue Zähler
3. die beiden Nenner miteinander multiplizieren
4. dieses Produkt ist der neue Nenner
5. dieser neue Bruch ist noch nicht gekürzt
Diese zweite Reihenfolge ist in dem unten dargestellten Programmschnipsel gezeigt. Die Methode kuerzen
sollte jeder selbst programmieren und wird hier nicht gezeigt.
Wichtig ist hier, dass die Methode addieren“ der anderen Zahlen überschrieben wird. Diese Methode
”
ist die magische Methode add (wieder 2 Unterstriche vor und nach dem Wort add“). Wenn ich jetzt
”
in meiner Klasse Bruch eine neue Methode add codiere, dann kann ich zwei Objekte der Klasse
Bruch einfach durch ein einfaches Pluszeichen addieren.
3 class Bruch():
4 def __init__(self, zaehler=0, nenner=1):
5 [Link] = zaehler
6 [Link] = nenner
7
10 erg = b1+b2
11
Als erstes sollte man jetzt eine Methode kuerzen schreiben; dazu benötigt man noch den Euklid’schen
Algorithmus für die Suche des größten gemeinsamen Teilers.
235
KAPITEL 10. KLASSEN 10.8. GUTE PROGRAMME ... WANN . . .
Dann drängt es sich geradezu auf, dass man eine eigene Methode anzeigen für Brüche codiert. Und
dann wird jeder wahrscheinlich die anderen Methoden für die Subtraktion, Multiplikation und Division
von Brüchen schreiben wollen!
Hier kommt noch eine Liste der magischen Methoden, die überschrieben werden können:
• Vergleichs-Methoden
– eq : gleich
– ne : ungleich
– gt : größer
– ge : größer oder gleich
– lt : kleiner
– le : kleiner oder gleich
• mathematische Methoden
– add : addieren (auch für Strings!)
– sub : subtrahieren
– mul : multiplizieren
– truediv : dividieren ( echtes“, d.h. 7 / 4 = 1.75)
”
– floordiv : Ganzzahldivision (d.h. 7 / 4 = 1)
– mod : Modulus (Rest bei der Ganzzahldivision, d.h. 7 % 4 = 3)
– pow : potenzieren (3**4 = 81)
• sonstige
– str : gibt die Zeichenkette zurück
– len : gibt die Länge des Objektes zurück
1. Das, was ich selber oft nicht mache, wenn ich mal schnell“ eine Lösung suche, sollte bei umfang-
”
reicheren Programmen am Anfang stehen: ein gutes Design. Ich selber male wirklich nicht gerne
UML-Diagramme ... aber es hilft!!!
2. Wenn ein Programm zu lang wird, überlege, ob es nicht innerhalb des Programms zusammenhän-
gende Aktionseinheiten“ gibt, die Du zusammenfassen kannst.
”
236
KAPITEL 10. KLASSEN 10.8. GUTE PROGRAMME ... WANN . . .
3. Das ist oft dann der Fall, wenn ein Ding ganz wenige (oder bestenfalls nur eine) Eigenschaft hat
und diese Eigenschaft immer auf eine sehr ähnliche (oder bestenfalls auf die selbe) Art verändert
wird. Das hört sich doch sehr nach einer Klasse mit einem (oder ganz wenigen) Attribut(en) und
mit einer Methode an.
4. Wenn Du das Gefühl hast, dass zwei Dinge in Deinem Programm sehr ähnlich aussehen und sich
sehr ähnlich verhalten, überlege Dir, ob das eine Ding nicht eine Spezialisierung (oder in der an-
deren Richtung eine Verallgemeinerung) des anderen Dings ist. Wenn Du diese Überlegung total
oder ansatzweise mit ja“ beantworten kannst, spricht vieles dafür, dass Du es hier mit Vererbung
”
zu tun hast.
5. Wenn Du Dich für Objektorientierung entschieden hast, und dann feststellst, dass Deine Klassen-
datei sehr groß geworden ist, überleg Dir noch einmal, ob das alles, was in der Klassendatei steht,
wirklich zu EINER Klasse gehört oder ob nicht noch eine weitere Klasse mitspielt.
6. Das ist vor allem dann wahrscheinlich, wenn innerhalb der Klassendatei auf Daten zugegriffen
wird, die keine Attribute der Klasse sind.
7. Schau Dir nochmal alle Bezeichner durch: sind Attributnamen wirklich Substantive und Metho-
dennamen wirklich Verben im Infinitiv? Mach das auch in die andere Richtung: suche alle Verben
und überprüfe, ob das wirklich alles Methoden sind; suche alle Substantive und checke, ob das al-
les Attribute sind. Wenn nicht, ändere das schnell. Und wenn nach der Änderung sich irgendetwas
eher seltsam anhört: dann ist wahrscheinlich irgendetwas eher faul!!!
237
11. Ein etwas längeres Programm
11.1. Objektorientierter Entwurf
Stellen wir uns vor, wir sollten ein Programm schreiben, das Konten einer Bank verwaltet. Den Entwurf
wollen wir wieder in einzelnen Schritten durchführen, wobei wir am Anfang sehr grob vorgehen, und
später das Erarbeitete verfeinern. In diesem Sinn legen wir für die Klasse Konto zuerst nur die nötigsten
Attribute und Methoden fest.
Das Besondere an einem Konto fällt (hoffentlich) sofort auf: der Inhaber des Kontos ist ein Mensch!
(Als Aussage des alltäglichen Lebens ist das wirklich keine Weisheit. Als Aussage in unserem Klassen-
Entwurf ist das etwas völlig Neues!) In der Sprache UML ausgedrückt: eines der Attribute der Klasse
Konto ist ein Objekt der Klasse Mensch. Dies wird Aggregation genannt.
239
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.2. OBJEKTORIENTIERTE . . .
4 class Konto(object):
5
240
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.2. OBJEKTORIENTIERTE . . .
4 class Konto(object):
5
Und das Aufruf-Programm ruft jede der beiden Methoden einmal auf und gibt jeweils anschließend
den aktuellen Stand aus:
2 #!/usr/bin/python
3
13 [Link](111.23)
14 print([Link], [Link], ’\n’,
15 [Link])
16 print(’Kontonr.:’, [Link], ’ Kontostand: ’, [Link])
17
18 [Link](5.01)
19 print([Link], [Link], ’\n’,
20 [Link])
21 print(’Kontonr.:’, [Link], ’ Kontostand: ’, [Link])
22
241
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.2. OBJEKTORIENTIERTE . . .
4 class Konto(object):
5 taZaehler = 0
6
Hinzugekommen ist das Attribut taZaehler, das die Transaktionen zählt. Zu Beginn wird dieser
Zähler auf 0 gesetzt, in den einzelnen Methoden wird er hochgezählt (Vorsicht! Es muss natürlich mit
[Link] angesprochen werden!) und nach dem Hochzählen wird abgefragt, ob er durch 3
teilbar ist. Wenn ja, wird die Verzinsung angestossen. Das Aufruf-Programm ändert sich vorerst kaum,
da wir ja immer noch in der Test-Phase sind, es werden einzig die Befehle zum Einzahlen und zur
Anzeige mehrmals kopiert, so dass man mehrere Transaktionen bekommt.
Es gibt natürlich auch hier noch einiges zu verbessern.
1. Zuerst einmal entspricht es keinem guten Stil, Attribute eines Objektes direkt anzusprechen; das
sollte immer mittels einer Methode der Klasse geschehen.
2. Die Anzeige nach der Verzinsung gibt einen Kontostand mit mehr als 2 Dezimalstellen aus. Das
verwirrt auch den wohlwollendsten Bankkunden auf Dauer.
3. Das Aufruf-Programm ist ein Skandal! Immer wieder eine Folge von Befehlen zu kopieren ist
mit dem Berufsethos eines Programmierers nicht zu vereinbaren: da muss eine Schleife mit einer
sinnvollen Abbruchbedingung her.
4. Dabei wird auch endlich ein ordentliches Buchungsverfahren“ verwirklicht, das heißt, dass nicht
”
mehr im Aufruf-Programm die Buchungen fest verdrahtet sind, sondern dass man über Tastatur-
Eingaben Einzahlungen und Auszahlungen macht.
Das alles wird im nächsten Kapitel behandelt.
242
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.2. OBJEKTORIENTIERTE . . .
Das Aufruf-Programm ändert sich dadurch, es wird kürzer, weniger fehleranfällig, überschaubarer;
kurz, es wird schöner!
2 #!/usr/bin/python
3
10 [Link](111.23)
11 [Link]()
12
13 [Link](5.01)
14 [Link]()
15
16 [Link](100.00)
17 [Link]()
18
19 [Link](100.00)
20 [Link]()
21
Die zweite Verbesserung ist nur eine Kleinigkeit. Nur die neu geschaffene Methode kontoStandAusgeben
muss an einer Stelle verändert werden. Siehe dazu im Kapitel über Zeichenketten den Abschnitt über
Formatierung von Zeichenketten. Der Quelltext der veränderten Klassenmethode sieht so aus:
Jetzt kommt die wirklich interessante Veränderung. Es wird nicht mehr fest im Programm verdrah-
tet, wieviele Eingaben gemacht werden sollen, sondern der Benutzer entscheidet, wann das Programm
beendet werden soll: machen wir noch eine Schleife drum!
243
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.2. OBJEKTORIENTIERTE . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from clKonto import Konto
5
10 def meld():
11 print("Konto-Verwaltung\ne für Einzahlung\na für Auszahlung\ns für Schluss")
12
13 eingabe = ’q’
14 while (eingabe != ’s’):
15 meld()
16 eingabe = input(’Bitte Eingabe:’)
17 if eingabe == ’e’:
18 betrag = float(input(’Einzahlungsbetrag: ’))
19 [Link](betrag)
20 elif eingabe == ’a’:
21 betrag = float(input(’Auszahlungsbetrag: ’))
22 [Link](betrag)
23 elif eingabe == ’s’:
24 print(’und tschüß’)
25 else:
26 print("Falsche Eingabe. nur a, e, s erlaubt")
27 [Link]()
28
Wieder könnte man sich entspannt zurücklehnen. Aber ganz zufrieden ist man nie, das ganze soll
noch besser werden. (Ganz ehrlich: so könnten wir das Programm noch keiner Bank verkaufen!) Was zu
tun ist? Das:
1. Das aufrufende Programm aus dem letzten Programm-Listing ist aus der Sicht des objektorien-
tierten Programmierers nicht in Ordnung. Das, was in diesem Programm steht, ist eigentlich ein
Menu für die Anwendung. Ein Menu ist aber wieder ein Objekt einer Menu-Klasse. Man könnte
sich also überlegen, wie man eine solche Menu-Klasse modelliert, wie man ein Objekt dieser Klas-
se erzeugt und wie man dann dieses Objekt arbeiten lässt. Der Konjunktiv steht hier, weil das
für dieses einfache Programm erst mal nicht nötig ist, um das Prinzip der Objektorientierung an
dem Beispiel der Klasse Konto zu überdenken. In einem der nächsten Beispiele wird das genau
durchgeführt, dass eine Klasse Menu erstellt wird. Ein bißchen Geduld also bitte!
2. Ein Konto ist ja ganz gut und schön, aber mit nur einem Konto wird keine Bank glücklich. Es
sollten schon mehrere Konten möglich sein.
3. Wenn der Rechner ausgeschaltet wird, sind alle Informationen verloren. So geht das nicht. Die
Daten sollten also gespeichert werden, (spätestens) wenn das Programm beendet wird.
Das alles wird im nächsten Kapitel behandelt.
244
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.3. EIN KLASSISCHES BEISPIEL: STACK . . .
3. Diese Übungsaufgabe hört sich leicht an, ist aber recht kompliziert. Es geht um das bekannte Spiel
unter der Schulbank Schiffe versenken“. Gegeben ist ein Spielfeld der Größe 10 x 10, auf dem ein
”
Schiff der Länge 4, 2 Schiffe der Länge 3 und 3 Schiffe der Länge 2 versteckt sind. Der Dialog mit
dem Spieler könnte so aussehen:
0 0 0 0 . 0 . 0 . 0
k X k . 0 0 0 k 0 0
0 0 0 0 0 0 V V V V
0 0 k 0 0 0 0 0 0 0
V V V k 0 0 0 . . 0
0 0 0 0 0 V 0 0 k k
0 0 0 0 k V k V V V
0 0 0 0 0 k k 0 0 0
0 0 . 0 . k k 0 0 0
0 0 0 0 0 k X 0 0 0
Dabei bedeuten:
• 0 : noch nicht beschossenes Feld
• . : Splash! Das war voll ins Wasser!
• k : knapp daneben
• X : Treffer
• V : Schiff total versenkt
1. FIFO: die Schlange (queue) Jeder Engländer versteht dieses Prinzip (und vielleicht gar kein ande-
res). Es wird brav sich angestellt, und in der Reihenfolge des Anstellens kommt man dran. So sieht
es auch an der Supermarkt-Kasse aus: wer zuerst ankommt, wird auch zuerst bedient. FIFO heißt
eben first in, first out“.
”
2. LIFO: der Stapel (stack) Für Frauen ist das wahrscheinlich unverständlich, aber bei Männern funk-
tioniert der Inhalt eines Kleiderschranks nach diesem Prinzip. Der Mann selber (oder die liebe Ma-
ma oder die noch liebere Freundin oder Frau) räumt die T-Shirts in den Kleiderschrank ein, und
am Morgen langt er hinein und nimmt das oberste, das als letztes reingelegt wurde, heraus und
zieht es an. LIFO heißt eben last in, first out“.
”
245
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.3. EIN KLASSISCHES BEISPIEL: STACK . . .
def entfernen(self):
entf = [Link](0)
def anzeigen(self):
print([Link])
Ein Programm, das diese Queue testet, ist auch nicht viel schwerer:
246
KAPITEL 11. EIN ETWAS LÄNGERES . . . 11.3. EIN KLASSISCHES BEISPIEL: STACK . . .
def entfernen(self):
entf = [Link]()
def anzeigen(self):
print([Link])
Der Aufruf
meinStack = Stack()
for i in range(5):
[Link](i)
[Link]()
while [Link]:
[Link]()
[Link]()
247
Teil VII.
249
12. Fehler. . .
Because something is happening here
And you don’t know what it is
(Bob Dylan 1 )
1. In dem oben geschilderten Fall ist die zuständige Person nach dem Motto vorgegangen: ich habe
das programmiert (oder die Programme eingerichtet), ich habe es einmal (oder 10 mal oder noch
öfter) getestet, es hat funktioniert, also wird es auch weiterhin immer funktionieren.
Nichts zu tun: das ist, bei meinem Bekannten hat sich das bestätigt, für die für die Einrichtung des
Systems zuständige Person die einfachste, für den Benutzer oder den Kunden aber sicher die im
Zweifelsfall unbefriedigendste Lösung.
2. Die nächste Stufe ist das Minimum, was man von einem System erwarten sollte. Bei jedem Schritt
einer solchen Datensicherung wird eine Meldung ausgegeben. Das könnte dann so aussehen:
===> Daten erfolgreich geschrieben
===> Tabelle xyz mit ii Datensätzen geschrieben
oder:
=X=X=> Fehler !!!
=X=X=> Schreiben der Tabelle xyz nach jj Datensätzen abgebrochen
OK, das sieht doch schon mal nicht schlecht aus. Es erfordert aber, dass der Anwender diese In-
formationen jeden Tag liest, und das sehr sorgfältig. Aber jeder weiß: jetzt hat das an 500 Tagen
funktioniert, dann brauch ich ab jetzt nicht mehr so genau hinschauen. Das wird doch auch wei-
terhin stimmen.
Dazu muss aber das Programm, das für die Datensicherung zuständig ist, bei jeder Aktion die kor-
rekte Ausführung überprüfen, und das müsste der Programmierer tatsächlich Schritt für Schritt
1 Ballad of a thin man auf: Highway 61 revisited
251
KAPITEL 12. FEHLER. . . 12.2. FEHLER WERDEN ABGEFANGEN
programmieren.2 Nach jedem einzelnen der überprüften Schritte muss dann der Programmierer,
nach Anweisung der Fachabteilung, in sein Programm einbauen, was passieren soll: soll die ge-
samte Sicherung abgebrochen werden, soll eine Fehlermeldung ausgegeben werden und die Si-
cherung der weiteren Dateien versucht werden, müssen bereits gesicherte Daten wieder entfernt
werden, damit keine Inkonsistenzen entstehen?
Diese Fehlerbehandlung zu Fuß“ wird umfangreich und damit auf Dauer undurchsichtig, also
”
auch schwer wartbar. Es ist auch fraglich, ob bei einer solchen Fehlerbehandlung in Handarbeit
alle möglichen Fehlerquellen abgedeckt werden und vor allem keine möglicherweise in Zukunft
auftretende Fehlerquelle nicht bedacht wird.
3. Um das zu verbessern und zu vereinfachen, ist in der Software-Technik das Prinzip der Ausnah-
”
mebehandlung“ entstanden. Eine Ausnahme ist irgendetwas in einem Programmablauf, was der
Entwickler nicht erwartet. Genauer gesagt: er erwartet nicht, dass es passiert, aber er weiß, dass es
passieren könnte. Im schlimmsten Fall ist eine Ausnahme ein Fehler, der zu falschen Ergebnissen
führt, vielleicht auch zu Datenverlust, in weniger schlimmen Fällen entsteht in einem Programm
eine Situation, die eine weitere Ausführung unmöglich macht, aber noch andere Ausnahme(type)n
sind denkbar.
Was man sich wünschen würde, wäre aber etwas in der Art:
Und man bekommt eine zweite Chance (und zur Not eine dritte und eine vierte . . . )
Der obigen Dialog mit dem Benutzer wurde realisiert durch folgendes Programm:
2 So hat man das wirklich vor nicht allzu langer Zeit gemacht. Eine extrem lästige Arbeit!
252
KAPITEL 12. FEHLER. . . 12.2. FEHLER WERDEN ABGEFANGEN
Schöner allerdings ist es, den entsprechenden Fehler abzufangen. Das ist ein Fehler der Klasse Value-
Error, also ein Wert-Fehler. Dazu lasse ich einen Text eingeben und versuche, diesen Text in eine Ganz-
zahl umzuwandeln:
Zu diesem Zweck hat Python eine eingebaute Fehlerbehandlung, die man aber besser als Ausnahme-
behandlung bezeichnet. Das Prinzip ist immer das folgende:
1. Wenn man einen Programmbefehl schreibt, bei dem es möglich ist, dass ein Fehler passiert, teilt
man dem Programm mit, dass es diesen Befehl nicht ausführen soll, sondern probieren soll, ob der
Befehl ausführbar ist.
3. Wenn der Befehl nicht ausgeführt werden kann, wird eine Ausnahme geworfen.3 Die Ausnahme
ist ein Befehl, der ausgeführt wird, wenn der ursprünglich gewünschte Befehl nicht ausgeführt
werden kann.
4. Es gibt dann noch die Möglichkeit, Befehle anzuschließen, die auf jeden Fall ausgeführt werden,
egal, ob der ursprünglich gewünschte Befehl geklappt hat oder nicht.
In der Frühzeit der Programmierung war einer der häufigsten Fehler, der einen Rechner (zum Beispiel
unter DOS) zum Absturz brachte, dass man versuchte, durch Null zu dividieren.
3 Diese Sprechweise hat sich auch im Deutschen durchgesetzt: sie ist eine wörtliche Übersetzung von to throw an exception“
”
253
KAPITEL 12. FEHLER. . . 12.2. FEHLER WERDEN ABGEFANGEN
2 >>> x = 27
3 >>> y = 3
4 >>> ergebnis = x/y
5 >>> print(ergebnis)
6 >>> 9
7
Die Fehlermeldung ist verständlich, aber das Programm hat sich verabschiedet.4 Man kann das in
Python durch ein try - except Konstrukt zum Glück verhindern:
2 >>> try:
3 >>> x = 27
4 >>> y = 0
5 >>> erg = x / y
6 >>> except:
7 >>> print(’Da lief etwas schief. Schau noch mal nach den Werten von x und y’)
8 ’Da lief etwas schief. Schau noch mal nach den Werten von x und y’
9
Sinnvollerweise sollte man diesen ganzen Programm-Schnipsel in eine while-Schleife einbinden, die
es dem Benutzer erlaubt, einen Wert für y so lange einzugeben, bis der ungleich 0 ist.
Das Otto-Waalkes-Gedächtnis-Beispiel sieht dann in Python so aus:
Hier wurde einfach blindlings mit except jeder x-beliebige Fehler abgefangen. Und das ist doch
schon ganz gut, denn damit kann das Programm weiterlaufen und als Programmierer kann man sich
überlegen, was in einem solchen Fall gemacht werden soll.
4 Zum Glück wurden die Betriebssysteme inzwischen so verbessert, dass nicht mehr das ganze Betriebssystem sich verabschiedet.
254
KAPITEL 12. FEHLER. . . 12.3. SPEZIELLE FEHLER
Das else ist in manchen Fällen sehr hilfreich. Nur so kann man sicherstellen, dass Anweisungen
dann und nur dann ausgeführt werden, wenn keine Ausnahme aufgetreten ist.
Beispiel 12.3.1 Division durch 0 ... wird durch passende Fehlerart abgefangen
1
2 >>> try:
3 >>> x = 27
4 >>> y = 0
5 >>> erg = x / y
6 >>> except ZeroDivisionError:
7 >>> print(’y darf nicht 0 sein!!!’)
8 >>> except:
9 >>> print(’irgendein anderer Fehler ist aufgetaucht’)
10 y darf nicht 0 sein!!!
11
Hier kommt ein weiteres Beispiel, bei dem aus Versehen versucht wird, über das Ende einer Liste
hinauszulesen:
So weit kein Problem. Aber was passiert, wenn man jetzt versucht, das siebte Element auszugeben?
255
KAPITEL 12. FEHLER. . . 12.3. SPEZIELLE FEHLER
Immerhin sagt Python mir hier, was falsch ist: der Index ist außerhalb des gültigen Bereichs. Es han-
delt sich also hier um einen Index-Fehler. Das kann man natürlich viel genauer abfangen:
Durch Text kann man nicht teilen! Es sollen also jetzt 2 Fehlerarten abgefangen werden.
Beispiel 12.3.6 Division ... wird durch passende Fehlerart abgefangen (1. Versuch)
>>> try:
>>> x = 27
>>> y = 0
>>> erg = x / y
>>> except ZeroDivisionError:
>>> print(’y darf nicht 0 sein!!!’)
>>> except TypeError:
>>> print(’Der Wert einer der beiden Variablen ist keine Zahl’)
>>> except:
>>> print(’Irgendein anderer Fehler ist aufgetreten’)
y darf nicht 0 sein!!!
256
KAPITEL 12. FEHLER. . . 12.3. SPEZIELLE FEHLER
Beispiel 12.3.7 Division ... wird durch passende Fehlerart abgefangen (2. Versuch)
>>> try:
>>> x = 27
>>> y = ’Always look on the bright side of life’
>>> erg = x / y
>>> except ZeroDivisionError:
>>> print(’y darf nicht 0 sein!!!’)
>>> except TypeError:
>>> print(’Der Wert einer der beiden Variablen ist keine Zahl’)
>>> except:
>>> print(’Irgendein anderer Fehler ist aufgetreten’)
Der Wert einer der beiden Variablen ist keine Zahl
Es ist gute Technik, Fehler immer mit einem ganz konkreten Fehlercode abzufangen. Mit einem ein-
fachen try . . . except ohne die Angabe eines Fehlercodes ist es vor allem in der Phase der Programm-
entwicklung ausgesprochen schwierig, einem Fehler auf die Spur zu kommen. Da ist es hilfreich, wenn
der Fehler durch den Fehlercode eingegrenzt wird. Dazu kommt jetzt eine Tabelle der wichtigsten Feh-
lercodes.
257
KAPITEL 12. FEHLER. . . 12.3. SPEZIELLE FEHLER
eingabe = ’’
def tu1():
print(’hier ist TU 1’)
def tu2():
print(’hier ist TU 2’)
def tu3():
print(’hier ist TU 3’)
258
Teil VIII.
Permanente Speicherung
259
13. Dateizugriff
13.1. Dateien allgemein
Look out kid
It’s somethin’ you did
(Bob Dylan 1 )
Dateien sind Speicherbereiche auf einem Speichermedium, die erstellt, geöffnet, geschlossen, bearbei-
tet und gelöscht werden können. Dafür ist das jeweilige Betriebssystem zuständig, das für jede dieser
Aktionen einen Befehl bereitstellt. 2
Jede Aktion mit Dateien fängt damit an, dass man die Datei öffnet. Damit erstellt man aus Sicht von
Python ein Objekt, das eine Verbindung zu der real existierenden Datei auf dem Datenträger herstellt.
Dabei muss man im Programm festlegen, was man nach dem Öffnen der Datei mit der Datei anstellen
will: will man sie nur lesen, will man sie verändern, oder will man eine neue Datei erstellen (und damit
eventuell eine bereits existierende Datei des selben Namens überschreiben). Der entsprechende Befehl
in Python sieht also so aus:
Damit ist klar: ab diesem Zeitpunkt ist meineDatei ein Objekt der Klasse file.
Diese Klasse hat einige Methoden, die jetzt für den Zugriff auf den Inhalt der Datei benutzt werden.
Grundsätzlich gilt: was man aufmacht, muss man auch wieder zumachen. Man sollte jede Datei nach
Gebrauch wieder schließen, und dazu dient die Methode close:
Schreiben wir also zwei Programme: zuerst eines, das eine Datei schreibt, dann ein zweites, das diese
Datei wieder liest. Für das Schreiben steht die Methode write zur Verfügung.
1 Subterranean Homesick Blues auf: Bringing It All Back Home
2 Ganz sicher bin ich mir nicht, ob das wirklich stimmt. In Unix-ähnlichen Betriebssystemen wird eine leere Datei durch den
Befehl touch dateiname erstellt (JA! Das ist wirklich sinnvoll!!) Gibt es einen analogen Befehl unter Windows?
261
KAPITEL 13. DATEIZUGRIFF 13.1. DATEIEN ALLGEMEIN
Jetzt kann man auf Betriebssystemebene (oder mit einem Hilfsprogramm wie xxx-Commander) se-
hen, dass diese Datei erstellt worden ist.
Das Thema Dateizugriff“ wurde mit dem Schreiben begonnen, da das die einfachere Operation ist.
”
Man muss sich dabei aber klar machen, dass der Dateizugriffsmodus w“ bedeutet, dass unbedingt
”
geschrieben wird. Falls eine Datei des selben Namens bereits existiert, wird diese überschrieben. Das
ist einfacher, weil es immer funktioniert, allerdings kann man da auch ganz schnell viel zerstören. Das
Lesen ist schon allein deswegen komplizierter, weil das Programm nicht weiß, wieviel es zu lesen gibt.
Erwartet man eine eher kleine Datei, ist es oft sinnvoll, die ganze Datei auf einmal einzulesen und
dann das Gelesene in einer Schleife abzuarbeiten. Wenn man allerdings weiß, dass die zu lesende Datei
vielleicht mehrere 100 MB groß ist, ist es sinnvoller, diese Datei Stück für Stück (das heißt günstigstenfalls
Zeile für Zeile) einzulesen und jede Zeile einzeln zu bearbeiten. Im Vergleich zu der ersten Methode be-
deutet das, dass hier die Schleife nicht innerhalb des Gelesenen sondern vor dem Lesen steht (oder wie
der Programmierer sagt: man schleift über das Lesen).
Hier wird die erste Methode angewandt, um die Datei zu lesen, nämlich alles auf einmal. Die Python-
Methode dazu heißt wieder genauso, wie man das erwartet: readlines (beachte den Plural) liest alle
Zeilen der Datei.
Wenn man die Schleife um das Lesen herummachen will, benutzt man die Methode readline. Ei-
gentlich ist das auch wieder logisch, dass man in diesem Fall nur eine Zeile liest, deswegen also der
Singular. Dann sieht das Programm so aus:
262
KAPITEL 13. DATEIZUGRIFF 13.1. DATEIEN ALLGEMEIN
Hier muss man gewährleisten, dass nicht versucht wird, über das Ende der Datei rauszulesen. Das
würde einen Programmabsturz verursachen, also muss mit dem logischen Schalter ende das Dateiende
abgefangen werden.
Seit Python Version 2.4 gibt es für den Dateizugriff Iteratoren“, also Mechanismen, die mitzählen“,
” ”
wieviel man gelesen hat und die damit wissen, was als nächstes drankommt. Der Unterschied ist, dass
3
Iteratoren mit Hilfe einer Exception abgefangen werden, während beim readline am Ende der Da-
tei einfach eine leere Zeichenkette in der entsprechenden Variablen (im Beispiel oben in der Variablen
zeile) steht. Der Iterator, der immer auf die nächste Zeile zeigt, heißt, wen wundert es, next. Das
Programm ändert sich leicht:
Der Befehl open öffnet die Datei, macht aber noch nichts mit der Datei. Allerdings kann man den
Datei-Handle als Liste benutzen und mit einer for-Schleife zeilenweise über die Datei schleifen:
meineDat = open("[Link]","r")
for zeile in meineDat:
print(zeile)
[Link]()
3 Das Thema Fehler und Ausnahmen steht erst weiter hinten im Text.
263
KAPITEL 13. DATEIZUGRIFF 13.1. DATEIEN ALLGEMEIN
Seit Version 2.5 gibt es in Python das Schlüsselwort with. Mit Hilfe von with wird ein Dateiobjekt
geöffnet und vor allem nach dem Dateizugriff geschlossen. Das sieht dann so aus:
Und die Ausgabe des Programms ist die selbe wie oben.
Die nächste Datei benutzt, dass durch with ein Iterator über die Datei erzeugt wird. Damit kann die
for-Schleife diesen Iterator benutzen, womit das Programm nochmals kürzer wird.
13.1.2. Textanalyse
Im nächsten Beispiel soll ein Text daraufhin untersucht werden, welches die häufigsten Wörter sind, die
er enthält. Dazu wird
1. ein leeres Dictionary angelegt, in dem am Ende die Wörter mit ihrer Häufigkeit stehen werden
2. eine Datei geöffnet
3. die Datei zeilenweise gelesen
4. a) von jeder Zeile der Zeilenvorschub am Ende entfernt
b) aus jeder Zeile die Satz- und Sonderzeichen entfernt
c) jede Zeile in ihre einzelnen Wörter aufgesplittet
d) i. von jedem Wort nachgeschaut, ob es schon im Dictionary steht
ii. wenn ja, wird der Zähler um 1 erhöht
iii. sonst wird der Zähler auf 1 gesetzt
264
KAPITEL 13. DATEIZUGRIFF 13.2. FORTFÜHRUNG DES . . .
import string
einDat = open(’/home/fmartin/texte/sonstiges/[Link]’,’r’)
zaehler = {}
Das Programm ist getestet! Schreib Dir selbst (mit einem Editor, nicht mit einer Textverarbeitung!!!)
eine Datei mit irgendwelchem Text, speichere sie und ändere den Pfad und den Namen der zu öffnenden
Datei. Und schau Dir dann die Ausgabe des Programms an.
Schau Dir an, was die Hilfe-Funktion zu
1. [Link]
2. [Link]
3. [Link]
sagt.
und hintendran gleich die neue Version, nach der Änderung, die ich ein paar Zeilen zuvor angespro-
chen habe:
265
KAPITEL 13. DATEIZUGRIFF 13.2. FORTFÜHRUNG DES . . .
Was hier passiert, wurde schon im Abschnitt über variable Parameter beim Funktionsaufruf beschrie-
ben.
Im Aufruf-Programm muss sich allerdings viel ändern. Als erstes bekommt das Programm zwei
Funktionen, mit denen man dem Benutzer die möglichen Eingaben, je nachdem in welchem Programm-
Teil der Benutzer sich gerade befindet, auf den Bildschirm schreibt. Ein bißchen Hilfe muss sein.
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from clKonto import Konto
5
6 alleKonten = {}
7
8 def meldModus():
9 print("Konto-Verwaltung\ne für Einzahlung\na für Auszahlung\ns für Schluss")
10
11 def meldAnl():
12 print("Konto-Verwaltung\nn für ’Neues Konto anlegen’\ns für Schluss")
13
2 eingabe = ’q’
3 while (eingabe != ’s’):
4 meldAnl()
5 eingabe = input(’Bitte Eingabe:’)
6 if eingabe == ’n’:
7 neuKtoNr = input(’Bitte neue Konto-Nummer eingeben: ’)
8 neuVorname = input(’Bitte Vornamen eingeben: ’)
9 neuNachname = input(’Bitte Nachnamen eingeben: ’)
10 neuGebdat = input(’Bitte Geburtsdatum eingeben: ’)
11 neuWohnort = input(’Bitte Wohnort eingeben: ’)
12 aktuellesKonto = Konto(neuKtoNr, neuVorname, neuNachname,
13 neuGebdat, neuWohnort)
14 alleKonten[neuKtoNr] = aktuellesKonto
15 elif eingabe == ’s’:
16 pass
17 else:
18 print("Falsche Eingabe. nur n und s erlaubt")
19
In den Zeilen mit input werden die Parameter für jeweils ein neues Konto entgegengenommen. Mit
266
KAPITEL 13. DATEIZUGRIFF 13.3. IN DIE DATEI DAMIT!!!
diesen Werten wird der Konstruktor für ein Konto aufgerufen und damit ein Objekt erzeugt, das ein-
deutig zu identifizieren ist durch die Kontonummer. Diese Kontonummer als Schlüssel und das Konto-
Objekt als Wert werden in dem Dictionary abgelegt.
Jetzt folgen zwei ineinanderverschachtelte while-Schleifen. In der äußeren Schleife wählt man bis
zur Abbruchbedingung immer ein neues Konto aus. Die Abbruchbedingung ist hier willkürlich auf die
Kontonummer 9999 gesetzt. In der inneren Schleife befindet sich die Bearbeitung eines einzelnen Kontos
mit einzahlen, auszahlen und verzinsen, so wie sie bisher schon existierte:
eingabe = ’q’
while (eingabe != ’s’):
meldModus()
eingabe = input(’Bitte Eingabe:’)
if eingabe == ’e’:
betrag = float(input(’Einzahlungsbetrag: ’))
[Link](betrag)
elif eingabe == ’a’:
betrag = float(input(’Auszahlungsbetrag: ’))
[Link](betrag)
elif eingabe == ’s’:
print(’und tschüß’)
else:
print("Falsche Eingabe. nur a, e, s erlaubt")
[Link]()
else:
pass
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from clKonto import Konto
5 import pickle
6
Ganz an das Ende des Programms wird dann die Dateibehandlung eingefügt. Sie besteht aus 4 Schrit-
ten: Dateinamen vergeben, Datei öffnen, Objekt in die Datei dumpen, Datei schließen.
267
KAPITEL 13. DATEIZUGRIFF 13.3. IN DIE DATEI DAMIT!!!
2 dateiName = ’[Link]’
3 ktoDatei = open(dateiName, ’wb’)
4 [Link](alleKonten, ktoDatei)
5 [Link]()
6
Damit das ganze Kapitel aber nicht total peinlich ist, folgt noch ein Aufruf-Programm, mit dem man
die geschriebene Datei wieder auslesen kann. Auf die Verarbeitung der gelesenen Daten wird hier ver-
zichtet, da man das aus dem vorigen Aufruf-Programm kopieren kann.
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from clKonto import Konto
5 import pickle
6
7 alleKonten = {}
8
9 dateiName = ’[Link]’
10 ktoDatei = open(dateiName, ’rb’)
11 while ktoDatei:
12 try:
13 alleKonten = [Link](ktoDatei)
14 except EOFError:
15 break
16 [Link]()
17
W ICHTIG
Unter Python 2.x war der Dateizugriff mittels pickle nicht mehr mit Attributen
rb und wb, sondern mit r und w.
Ein leeres Dictionary wird angelegt, dann der Dateiname an eine Variable zugewiesen, die Datei wird
geöffnet, und dann wird die Datei, die nur ein einziges Objekt enthält, in das Dictionary eingelesen. Der
Lese-Prozess wird durch ein try - except - Konstrukt abgesichert. Danach wird die Datei geschlossen
und nur zur Kontrolle werden die gelesenen Kontonummern ausgegeben.
268
KAPITEL 13. DATEIZUGRIFF 13.3. IN DIE DATEI DAMIT!!!
2 class Person():
3 def __init__(self,v,n,o):
4 [Link] = v
5 [Link] = n
6 [Link] = o
7
8 class ShelveNamen():
9 def __init__(self):
10 import shelve
11 [Link] = [Link](’namen’,’w’)
12 def satzSchreiben(self, schluessel, p):
13 [Link][schluessel] = p
14 def schliessen(self):
15 [Link]()
16
17 datenbank = ShelveNamen()
18
19 for i in range(5):
20 vn = input(’Vorname: ’)
21 nn = input(’Nachname: ’)
22 ort = input(’Ort: ’)
23 per = Person(vn,nn,ort)
24 schluessel = input(’Schluessel: ’)
25 [Link](schluessel, per)
26 [Link]()
27
In den ersten 5 Zeilen wird eine Klasse Person beschrieben, die nur die 3 Attribute Vorname, Nach-
name und Ort hat. Methoden benötigt diese Klasse nicht, da die einzelnen Objekte nichts machen sollen,
sondern nur gespeichert werden sollen.
In den Zeilen 7 bis 14 wird eine Klasse ShelveNamen beschrieben, die im Konstruktor eine Datei an-
legt, die die Datensätze (also die Objekte) aufnehmen soll. Diese Klasse hat die Methode satzSchreiben,
die genau das macht, und die Methode schliessen, die die Datei am Ende schließt.
Im eigentlichen Programm wird dann zuerst eine datenbank angelegt, danach werden 5 Objekte der
Klasse Person erzeugt, jedes mit einem Schlüssel versehen und jeweils in die Datenbank geschrieben.
Zum Schluß wird die Datei geschlossen.
269
KAPITEL 13. DATEIZUGRIFF 13.4. AUFGABEN ZU DATEIEN
2 Vorname: Martin
3 Nachname: Schimmels
4 Ort: Oxxxxx
5 Schluessel: Martin
6 Vorname: Hannah
7 Nachname: yyyy
8 Ort: zzzz
9 Schluessel: Hannah
10 Vorname: Theresa
11 Nachname: xyz
12 Ort: xyz
13 Schluessel: Theresa
14 Vorname: Berthold
15 Nachname: zyx
16 Ort: zyxx
17 Schluessel: Berti
18 Vorname: Peter
19 Nachname: abc
20 Ort: abc
21 Schluessel: Peter
22
23 >>> db = [Link](’namen’,’r’)
24 >>> db[’Peter’].vn
25 ’Peter’
26 >>> db[’Peter’].nn
27 ’abc’
28 >>> db[’Martin’].nn
29 ’Schimmels’
30
Die ersten 20 Zeilen sind die Eingaben der je 3 Attribute jedes Objektes sowie des Schlüssels jedes
Objektes. Die folgende Zeile öffnet die Datei zum lesen. Und dann kommt das Datenbank-ähnliche“
”
dieser Speicherung: die einzelnen Attribute eines Datenbanksatzes (also eines Objekts) können mittels
des Schlüssels und des Attributnamens ausgelesen werden.
270
14. Datenbanken
If your mem’ry serves you well
(Bob Dylan 1 )
14.1. MySQL
Python hat Module für den Datenbankzugriff für viele verschiedene relationale Datenbanken. MySQL
ist eine Datenbank, die unter die freie Software fällt, und MySQL ist weit verbreitet, weil es eine sehr
mächtige Datenbank ist. Für MySQL gibt es auch die Möglichkeit, eine Lizenz zu erwerben und sich
damit Support zu sichern. Das führte dazu, dass MySQL nicht nur im Hobby“-Bereich verbreitet ist,
”
sondern auch große Unternehmen mit dieser Datenbank arbeiten.
Für die Arbeit mit Datenbanken gilt vieles, was auch für die Arbeit mit Dateien (siehe dort) gilt. Ein
Datenbankzugriff besteht immer aus drei Schritten:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 import MySQLdb
6 verbindung = [Link]("localhost", db="nameort",
7 user="karldepp", passwd="doof")
8 cursor = [Link]()
9
13 [Link]()
14 [Link]()
15
Das Modul für die Datenbank, hier für MySQL, muss import werden. Dieses Modul enthält eine Me-
thode connect, die als erstes aufgerufen wird. Auf die erstellte Verbindung wird der Cursor aufgesetzt,
sozusagen ein Zeiger auf die Datenbank, an den eventuelle Befehle übergeben werden. Im nächsten
Schritt wird für diesen Cursor die Methode execute aufgerufen, die den als Parameter übergebenen
SQL-Befehl ausführt. Danach wird zuerst der Cursor, dann die Verbindung geschlossen.
Das alles sind durchaus kritische Operationen. Aber der Umgang mit kritischen Operationen wurde
ja im vorigen Kapitel angerissen: Dinge, von denen man nicht weiß, ob sie wirklich so klappen, wie
1 This Wheel’s on Fire auf: The Basement Tapes
271
KAPITEL 14. DATENBANKEN 14.1. MYSQL
man sich das als Entwickler gedacht hat, versucht man erst und fängt eine mögliche Ausnahme ab. Eine
bessere Version sieht so aus:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 import MySQLdb
6 try:
7 verbindung = [Link]("localhost", db="nameort",
8 user="karldepp", passwd="doof")
9 except:
10 print(’Verbindung konnte nicht hergestellt werden’)
11 else:
12 try:
13 cursor = [Link]()
14 except:
15 print(’Cursor konnte nicht gesetzt werden’)
16 else:
17 [Link]("INSERT INTO namen (vorname, name, plz)
18 VALUES (%s, %s, %s)", (’Ernst’, ’Maier’, ’72108’))
19
20 [Link]()
21 [Link]()
22
Man sieht: das ist eine verschachtelte try - except Anweisung, da ja bei jedem Schritt eine Aus-
nahme auftreten kann.
272
KAPITEL 14. DATENBANKEN 14.1. MYSQL
Das ist aber nicht wirklich schön, diese geschachtelte try - except Anweisung. Hier ist es bes-
ser, mehrere Anweisungen zu versuchen und für jede mögliche Ausnahme eine spezielle Fehlerklasse
abzufragen. Das Programm ändert sich also noch einmal:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 import MySQLdb
6 try:
7 verbindung = [Link]("localhost", db="plzort",
8 user="karldepp", passwd="doof")
9 cursor = [Link]()
10 except [Link]:
11 print(’Verbindung konnte nicht hergestellt werden’)
12 except:
13 print(’Cursor konnte nicht gesetzt werden’)
14 else:
15 try:
16 [Link]("INSERT INTO plzort (plz, ort)
17 VALUES (%s, %s)", (’72070’, ’Tübingen’))
18 except:
19 print(’Insert fehlgeschlagen’)
20 else:
21 print(’ok’)
22 [Link]()
23 [Link]()
24 [Link]()
25
26
MySQL (wie jeder SQL-Dialekt) puffert Befehle. Wenn man mit einer Entwicklungsumgebung wie
zum Beispiel der MySQL-Workbench arbeitet, merkt man das gar nicht. Bei einem solchen Werkzeug,
das für das interaktive Arbeiten ausgerichtet ist, ist es wichtig, dass das Ergebnis der Eingabe eines
Befehls gleich sichtbar ist. Befehle werden hier sofort ausgeführt. Wenn man nicht interaktiv arbeitet,
muss man das Schreiben aus dem Puffer in die Datenbank meistens von Hand anstoßen. Das geschieht
mit dem SQL-Befehl commit.
Das Lesen aus einer Datenbank ist ein ganzes Stück komplizierter. Das sollte eigentlich klar sein: wenn
ich (in eine Datenbank) schreibe, weiß ich, was ich schreibe; da kann nichts unerwartetes passieren.
Wenn ich ein Wort schreibe, dann ist das Ergebnis ein Wort, wenn ich zehn Wörter schreibe, ist das
Ergebnis zehn Wörter, wenn ich 3 Zahlen schreibe, ist das Ergebnis 3 Zahlen.
Wenn ich (aus einer Datenbank) lese, weiß ich nicht, was da auf mich zukommt. Das kann ein Wort,
das können 10 Wörter oder 3 Zahlen sein. Auf eine Datenbank bezogen bedeutet das, dass ich das
Ergebnis eines SELECT-Befehls nicht vorhersagen kann. Da kann es noch schlimmer kommen, als es
im vorigen Satz geschildert wurde: es kann sogar gar nichts als Ergebnis zurückgegeben werden! Die
Ergebnismenge kann 0, 1 oder viele Elemente enthalten.
Deswegen ist das Vorgehen ein leicht anderes. Die erste Änderung ist, dass das Ergebnis der Ausführung
des Befehls, also das, was durch [Link]() geschieht, einer Variablen zugewiesen werden muss.
Die zweite Änderung ist dann eigentlich logisch: über das, was in dieser Variablen steht, muss jetzt eine
Schleife gemacht werden, damit ich die einzelnen Datensätze nacheinander verarbeiten kann.
273
KAPITEL 14. DATENBANKEN 14.2. .. MIT PYTHON-BORDMITTELN
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 import MySQLdb
6 connection = [Link]("localhost", db="nameort",
7 user="karldepp", passwd="doof")
8 cursor = [Link]()
9 t2 = [Link]("SELECT * FROM namen")
10 for i in range(t2):
11 print([Link]())
12
13 [Link]()
14 [Link]()
15
274
Teil IX.
275
15. Ein weiteres Projekt: ein Getränkeautomat
15.1. Objektorientierter Entwurf und Realisierung der Klasse
Ein Getränkeautomat nimmt Geld entgegen und spuckt ein Getränk aus, sofern das Geld reicht und die
Ware vorhanden ist. Falls zuviel Geld eingeworfen wurde, wird das restliche Geld auch ausgegeben.
Diese Beschreibung gilt nicht nur für einen Getränkeautomaten, sondern allgemein für einen Auto-
maten: der nimmt Geld entgegen, überprüft den Warenbestand, gibt Waren aus und berechnet Restgeld
und gibt das zurück. Deswegen wird die Klasse gleich als allgemeiner Automat codiert. Wiederverwert-
barkeit ist ja eines der Ziele der objektorientierten Programmierung.
Die einfache Klasse sieht folgendermaßen aus:
277
KAPITEL 15. EIN WEITERES PROJEKT: EIN . . . 15.1. OBJEKTORIENTIERTER ENTWURF . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 class Automat():
6 def __init__(self, waren=[], kredit = 0):
7 [Link] = waren
8 [Link] = kredit
9
10 def geldEinwerfen(self):
11 print(’Geld eingeworfen’)
12
13 def guthabenAnzeigen(self):
14 print(’Guthaben anzeigen’)
15
16 def wareWaehlen(self):
17 print(’Ware auswählen’)
18
19 def neueWareAufnehmen(self):
20 print(’neue Ware hinzugenommen’)
21
22 def bestandPruefen(self):
23 print(’Bestand der gewählten Ware geprüft’)
24
278
KAPITEL 15. EIN WEITERES PROJEKT: EIN . . . 15.1. OBJEKTORIENTIERTER ENTWURF . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
7 class Menu():
8
9 def __init__(self):
10 [Link] = Automat()
11 [Link] = ’g = Geld einwerfen,
12 w = Ware wählen, n = neue Ware einführen,
13 e = Ende\n’
14
15 def auswahlTreffen(self):
16 auswahl = [’e’, ’w’, ’g’, ’n’]
17 eingabe = ’x’
18 while eingabe <>’e’:
19 eingabe = input([Link])
20 if eingabe == ’g’:
21 [Link]()
22 elif eingabe == ’w’:
23 [Link]()
24 elif eingabe == ’n’:
25 [Link]()
26 elif eingabe == ’e’:
27 pass
28 else:
29 print(’fehlerhafte Eingabe; nur e, g, n, w zulässig’)
30
Damit das Menu weiß, dass es sich um ein Menu für einen Automaten handelt, muss zuerst die Klas-
senbeschreibung aus der Datei cl automat importiert werden; danach wird im Konstruktor des Menus
ein Objekt der Klasse Automat erzeugt. Die Methode auswahlTreffen ruft dann die Methoden des
Automaten auf.
Wie immer gehört dazu auch ein aufrufendes Programm, das einfach ein Objekt der Klasse anlegt
und dann die Haupt-Methode der Klasse, nämlich das Auswahlmenu aufruft.
getraenkeautomat = Menu()
[Link]()
Das ist doch richtig schön, ein solch kurzes Programm. Die ganze Intelligenz steckt in der Klasse. Und
jedes Objekt der Klasse macht alles genau so gut wie jedes andere!!
Kommen wir also zur zweiten Version, in der ein bißchen etwas passiert.
279
KAPITEL 15. EIN WEITERES PROJEKT: EIN . . . 15.2. DIE WAREN KOMMEN IN DEN . . .
Diese Klasse hat vorläufig eine einzige Methode, nämlich den Konstruktor.
Interaktiv soll jetzt eine Ware angelegt werden, wobei die drei Attribute des Objektes gefüllt werden.
Gleichzeitig wird die Methode warenAnzeigen geschrieben, die jedes Mal nach Anlegen eines neuen
Objektes aufgerufen wird. Im folgenden werden nur diese beiden Methoden angezeigt, der Rest der
Klassendefinition bleibt so wie in der vorigen Version.
2 class Ware():
3 def __init__(self, bezeichnung, verkPreis, bestand):
4 [Link] = bezeichnung
5 [Link] = verkPreis
6 [Link] = bestand
7
8 class Automat():
9 ...
10 ...
11 def warenAnzeigen(self):
12 print(’folgende Waren können gekauft werden: ’)
13 print(’%20s %10s %10s’ % (’Ware’, ’Preis’, ’Bestand’))
14 for ware in [Link]:
15 print(’%20s %10.2f %10i’ % ([Link], [Link], [Link]))
16
17 def neueWareAufnehmen(self):
18 bez = input(’Bezeichnung der neuen Ware: ’)
19 vkPr = float(input(’Verkaufspreis der neuen Ware: ’))
20 best = float(input(’Lagerbestand der neuen Ware: ’))
21 nW = ware(bez, vkPr, best)
22 [Link](nW)
23 print(’neue Ware hinzugenommen’)
24 [Link]()
25
Das aufrufende Programm ändert sich überhaupt nicht! (Ist das ein gutes Zeichen??? Schon, oder? )
280
KAPITEL 15. EIN WEITERES PROJEKT: EIN . . . 15.4. JETZT KANN GEKAUFT WERDEN!
2 def geldEinwerfen(self):
3 muenzen = [1, 2, 5, 10, 20, 50, 100, 200]
4 einwurf = float(input(’Münze einwerfen: ’))
5 if einwurf in muenzen:
6 [Link] += einwurf
7 else:
8 print(’ungültige Münze, gültig sind: ’, muenzen)
9 [Link]()
10
11 def guthabenAnzeigen(self):
12 print(’aktuelles Guthaben: %5.2f \euro\/ ’ % ([Link]/100.0))
13
Das ist wirklich sehr einfach. Es wird eine Liste der zulässigen Münzen erstellt (dabei muss nur beach-
tet werden, dass 100 Cent gleich 1 e ist). Falls man eine korrekte Münze eingibt, wird das zum aktuellen
Guthaben — hier Kredit genannt — dazuaddiert.
Das aufrufende Programm ändert sich überhaupt nicht! (Ist das ein gutes Zeichen??? Aber sicher!! )
Ich weiß, ich wiederhole mich . . .
2 def wareWaehlen(self):
3 print(’Ware auswählen’)
4 [Link]()
5 ausgewaehlt = input(’Nr. der gewünschten Ware eingeben: ’)
6 if not [Link](ausgewaehlt):
7 print(’zu wenig Ware auf Lager’)
8 elif [Link] <= [Link][ausgewaehlt].verkPreis:
9 print(’Du hast zuwenig Geld eingeworfen’)
10 else:
11 print(’Ware wird ausgegeben’)
12 [Link][ausgewaehlt].bestand -= 1
13 print(’Restgeld %4.2f \euro\/ wird ausgegeben’ %
14 ([Link] - [Link][ausgewaehlt].verkPreis))
15 [Link] = 0.0
16
Hier gehört nur noch ein blöder Spruch hin: Das aufrufende Programm ändert sich überhaupt nicht!
(Ist das ein gutes Zeichen??? Super!!!! )
281
KAPITEL 15. EIN WEITERES PROJEKT: EIN . . . 15.5. TO DO!!
15.5. To Do!!
Vorschläge, was zu diesem Programm noch hinzugefügt werden kann:
• Fehler müssen abgefangen werden (z.B. wenn man eine Produktnummer außerhalb des gültigen
Bereichs wählt)
• Die Münzen können erweitert werden, so dass auch Geldscheine angenommen werden.
• Eine Stückelung des Restgeldes kann realisiert werden, wobei zu beachten ist, dass nicht die opti-
male Stückelung herausgegeben wird, sondern unter Umständen auch viel Kleingeld, weil andere
Münzen nicht mehr vorhanden sind. Aha: ein Geldbestand des Automaten muss also hinzugefügt
werden.
• Es kann ermöglicht werden, dass man mehr Geld als für eine Ware einwirft und dann auch meh-
rere Waren kauft.
282
16. Noch ein Beispiel: Zimmerbuchung in
einem Hotel
16.1. Vorstellung des Projekts
Natürlich soll hier nicht eine vollständige Software für das Management eines Hotels geschrieben wer-
den. Das Modell wird sehr vereinfacht, und in verschiedenen Versionen dann verfeinert.
Wir gehen von einem Hotelzimmer aus. Dieses wird als Klasse modelliert, wobei diese Klasse bewusst
einfach gehalten wird.
283
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.2. DER ERSTE ENTWURF: EINE KLASSE . . .
class Hotelzimmer():
def __init__(self, nr, anzBetten, preis = 30, frei = True):
[Link] = nr
[Link] = anzBetten
[Link] = frei
[Link] = preis
def belegen(self):
if [Link]:
[Link] = False
else:
print(’Zimmer ist bereits belegt’)
def freigeben(self):
if [Link]:
print(’Zimmer ist bereits frei’)
else:
[Link] = True
def anzeigen(self):
print(’Nr.:’, [Link], ’Anzahl Betten: ’, [Link])
if [Link]:
print(’frei’)
else:
print(’belegt’)
if __name__ == ’__main__’:
zi1 = Hotelzimmer(1, 2)
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
Der Konstruktor bekommt als Parameter die oben genannten Attribute, wobei den Attributen preis
und frei ein Defaultwert mitgegeben wird. Die Methoden belegen und freigeben fragen den ak-
tuellen Stand ab und führen die gewünschte Aktion durch, wenn sie möglich ist. Beachte hierbei, dass
das Attribut frei mit den Wahrheitswerten True und False arbeitet.
284
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.3. DER ZWEITE ENTWURF: EIN . . .
A NMERKUNG
Da dieser Klassenentwurf noch sehr einfach ist, wird hier kein externes auf-
rufendes Programm geschrieben, sondern über die Abfrage if name ==
’ main ’: die Klasse aus sich heraus gestartet. Es wird mit dieser Zeile ab-
gefragt, ob dieses Modul als Hauptprogramm oder als eine importierte Datei
gestartet wird. Da das jetzt das Hauptprogramm ist, werden die folgenden Zeilen
ausgeführt
def menu():
auswahl = input(’\n#### AUSWAHL ####\nZimmer anzeigen: Z
\nZimmer belegen: B\nZimmer freigeben: F
\nEnde: E\n#### ....... ####
\b\b\b\b\b\b\b\b\b\b\b\b’)
menuListe = {’Z’: [Link], ’B’: [Link],
’F’: [Link], ’E’: beenden}
menuListe[auswahl]()
def beenden():
global weiter
print(’danke für Deinen Besuch’)
weiter = 0
weiter = 1
zimmer1 = Hotelzimmer(1, 2)
while weiter:
menu()
1 Don’t think twice, it’s alright auf: The Freewheeling Bob Dylan
285
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.4. DER DRITTE ENTWURF: DAS HOTEL
286
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.4. DER DRITTE ENTWURF: DAS HOTEL
def menu(self):
auswahl = input(’\n#### AUSWAHL ####\nalle Zimmer anzeigen: Z
\nZimmer belegen: B\nZimmer freigeben: F
\nneues Zimmer anlegen: N
\nEnde: E\n#### ....... ####
\b\b\b\b\b\b\b\b\b\b\b\b’)
menuListe = {’Z’: [Link], ’B’: [Link],
’F’: [Link], ’N’:[Link],
’E’: [Link]}
menuListe[auswahl]()
def beenden(self):
print(’danke für Deinen Besuch’)
[Link] = False
def anzeigen(self):
if len([Link]) == 0:
print(’Es gibt noch keine Zimmer’)
else:
for zimmer in [Link]:
[Link]()
def belegen(self):
print(’Funktion noch nicht verfügbar’)
def freigeben(self):
print(’Funktion noch nicht verfügbar’)
def neuesZimmerAnlegen(self):
anzBetten = int(input(’Anzahl Betten des Zimmers: ’))
preis = float(input(’Preis des Zimmers: ’))
neuesZi = Hotelzimmer(len([Link])+1, anzBetten, preis)
[Link](neuesZi)
Hinzu kommt ein aufrufendes Programm. Nicht erschrecken: völlig undurchschaubar !!!!!
meinHotel = Hotel()
287
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.5. DER VIERTE ENTWURF: METHODEN . . .
288
KAPITEL 16. NOCH EIN BEISPIEL: . . . 16.5. DER VIERTE ENTWURF: METHODEN . . .
def menu(self):
auswahl = input(’\n#### AUSWAHL ####\nalle Zimmer anzeigen: Z
\nZimmer belegen: B\nZimmer freigeben: F
\nneues Zimmer anlegen: N
\nEnde: E\n#### ....... ####
\b\b\b\b\b\b\b\b\b\b\b\b’)
menuListe = {’Z’: [Link], ’B’: [Link],
’F’: [Link], ’N’:[Link],
’E’: [Link]}
menuListe[auswahl]()
def beenden(self):
print(’danke für Deinen Besuch’)
[Link] = False
def belegen(self):
print(’folgende Zimmer sind verfügbar: ’)
# erster Parameter = True: freie Zimmer anzeigen
[Link](True)
auswahl = int(input(’gewünschte Zimmer-Nr. angeben: ’))
[Link][auswahl - 1].belegen()
def freigeben(self):
[Link](False)
auswahl = int(input(’freizugebendes Zimmer: ’))
[Link][auswahl - 1].freigeben()
def neuesZimmerAnlegen(self):
anzBetten = int(input(’Anzahl Betten des Zimmers: ’))
preis = float(input(’Preis des Zimmers: ’))
neuesZi = Hotelzimmer(len([Link])+1, anzBetten, preis)
[Link](neuesZi)
289
17. Und noch ein Beispiel: ein Adressbuch
Auch dieses Beispiel soll Schritt für Schritt entwickelt werden, wobei in diesem Fall zuerst das Adress-
buch (der Name stimmt nicht, denn unter dem Namen einer Person werden nicht seine Adressda-
ten gespeichert, sondern sein Alter. Einfach weniger zu schreiben, Faulheit regiert die Welt.) nicht-
objektorientiert realisiert wird. Auch das wird zeigen, dass es in Python einfach und vor allem durch-
schaubar ist, ein solches kleines Projekt durchzuführen. Vor allem sind die Veränderungen von einem
Schritt zum nächsten oft offensichtlich und gut nachzuvollziehen.
Es sollen in diesem Adressbuch nur drei Daten einer Person gespeichert werden, der Vorname, der
Nachname und das Alter. Im Adressbuch sollen diese drei Daten geändert werden können, es sol-
len natürlich neue Datensätze hinzugefügt werden können und ebenso soll man Datensätze löschen
können.
Der erste Versuch speichert die Daten einer Person in einer Liste. Das sieht also so aus:
#!/usr/bin/python
# -*- coding: utf-8 -*-
Die Personen-Daten von mehreren Personen speichern wir in einer Liste von Listen, also:
namen = [martin,ekki]
Auf diese Informationen kann man jetzt über die üblichen Listen-Operationen zugreifen (daran denken:
man fängt bei 0 an zu zählen!), im folgenden Programm-Listing in der ersten for-Schleife auf die Ele-
mente der äußeren Liste, in der zweiten for-Schleife auf die Elemente der Elemente der äußeren Liste,
also auf die Elemente der jeweils inneren Listen.
291
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.3. DER ZWEITE ENTWURF: EIN FAULER . . .
#!/usr/bin/python
# -*- coding: utf-8 -*-
292
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.4. DER DRITTE ENTWURF: EINE LISTE . . .
Das ist zwar ein bißchen mehr Schreibarbeit, aber es ist dafür auch noch nach Jahren beim ersten
Lesen zu verstehen!
293
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.5. DER VIERTE ENTWURF: AKTIONEN . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def initialisiere():
6 global namen
7 martin = {’vorname’:’Martin’, ’nachname’:’Schimmels’,’alter’:54}
8 ekki = {’vorname’:’Eckard’, ’nachname’:’Krauss’,’alter’:41}
9 namen = [martin,ekki]
10
14 def einfuegen():
15 print(’hier ist Funktion einfügen’)
16
17 def aendern():
18 print(’hier ist Funktion ändern’)
19
20 def loeschen():
21 print(’hier ist Funktion loeschen’)
22
23 def beenden():
24 print(’Jetzt wird das Programm beendet’)
25
26 def menu():
27 print(tut mir leid, das Menu ist noch nicht fertig’)
28
29 initialisiere()
30 menu()
31
An die Arbeit! Das Menu wird gebaut. Zuerst wird ein Schalter weiter eingefügt, dessen Wert stan-
dardmäßig 1 (und damit True) ist und dessen Wert nur bei Betätigung der Taste E auf 0 (und damit auf
False) geändert wird. Danach wird in der Endlos-Schleife (solange weiter = True ist) ein Buchstabe ein-
gelesen. Die vielen \b“ bewirken, dass der Buchstabe in der letzten Zeile der Eingabeaufforderung an
”
der Stelle der Punkte eingelesen wird. Jetzt passiert wieder etwas, was in Python so elegante Program-
me erlaubt. Wert in einem Dictionary kann irgendetwas sein: eine Zahl, ein Text, eine Liste, selbst noch
ein Dictionary, aber auch eine Funktion. Das wird hier ausgenutzt: das Menu selber ist ein Dictionary,
dessen Schlüssel die einzugebenden Buchstaben und dessen Werte die Funktionen sind. Damit ist der
Aufruf der Funktion je nach eingegebenem Buchstabe nur noch das Herausholen eines Wertes aus dem
Dictionary.
294
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.5. DER VIERTE ENTWURF: AKTIONEN . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 def initialisiere():
6 global namen
7 martin = {’vorname’:’Martin’, ’nachname’:’Schimmels’,’alter’:54}
8 ekki = {’vorname’:’Eckard’, ’nachname’:’Krauss’,’alter’:41}
9 namen = [martin,ekki]
10
14 def einfuegen():
15 print(’hier ist Funktion einfügen’)
16
17 def aendern():
18 print(’hier ist Funktion ändern’)
19
20 def loeschen():
21 print(’hier ist Funktion loeschen’)
22
23 def beenden():
24 print(’Jetzt wird das Programm beendet’)
25
26 def menu():
27 weiter = 1
28 while weiter:
29 auswahl = input(’#### AUSWAHL ####\n
30 alle Namen anzeigen: Z\n
31 Namen einfügen: N\n
32 Namen löschen: L\n
33 Namen ändern: A\n
34 Ende: E\n
35 #### ....... ####\b\b\b\b\b\b\b\b\b\b\b\b’)
36 menuListe = {’N’: einfuegen, ’L’: loeschen,’A’:aendern,
37 ’E’:beenden, ’Z’:anzeigen}
38 menuListe[auswahl]()
39 if auswahl == ’E’:
40 weiter = 0
41
42 initialisiere()
43 menu()
44
295
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.6. DER FÜNFTE ENTWURF: AKTIONEN . . .
17.6. Der fünfte Entwurf: Aktionen (jetzt tut sich wirklich etwas)!!
Jetzt wollen wir etwas sehen. Also fangen wir mit der Funktion anzeigen an. In dieser Funktion muss
die Liste namen als global bekanntgegeben werden. Danach wird eine Überschriftszeile generiert. Die
Ausgabe der einzelnen Datensätze geschieht in einer for-Schleife, analog wie im dritten Entwurf.
2 def anzeigen():
3 global namen
4 print(’##### Namensliste #####’)
5 for einName in namen:
6 print(’##\t’, end=’ ’)
7 print(einName[’vorname’],einName[’nachname’],einName[’alter’])
8 print(’##### ----------- #####’)
9
Das Einfügen eines neuen Namens in die Liste ist auch kein Hexenwerk. Die einzelnen Informationen
werden über input eingelesen, das ganze wird zu einem Dictionary verbunden und dieses Dictionary
wird an die Liste namen angehängt
2 def einfuegen():
3 global namen
4 print(’Neuer Name wird eingefügt!’)
5 vorname = input(’Vorname: ’)
6 nachname = input(’Nachname: ’)
7 alter = input(’Alter: ’)
8 [Link]({’vorname’:vorname, ’nachname’:nachname, ’alter’:alter})
9
Das Löschen eines Namens ist eigentlich auch nicht viel schwieriger. Dazu kommt die Funktion del
für Listen ins Spiel, die mit der Nummer des Listenelements aufgerufen wird. Wenn die Liste aller-
dings länger (als 5) ist, wird die Abzählerei doch ein wenig lästig. Deswegen muss zuerst die Funktion
anzeigen so abgeändert werden, dass zusätzlich zu den Informationen über die Personen auch noch
die laufende Nummer in der Liste angezeigt wird. Dazu wird die Funktion anzeigen mit einem Para-
meter, der den Wahrheitswert True hat, aufgerufen. Der Standardwert für diesen Parameter ist False.
296
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.6. DER FÜNFTE ENTWURF: AKTIONEN . . .
Richtig umfangreich wird jetzt allerdings die Funktion aendern. Allerdings wirklich nur umfang-
reich, schwierig ist das nicht. Es werden wieder alle Einträge mit laufender Nummer angezeigt, man
wählt eine Nummer aus, die Informationen zu einem Namen werden ausgegeben und eine Eingabe
angefordert. Falls nur die Enter-Taste gedrückt wurde, das heißt also, wenn die Eingabe der leere String
ist, wird der alte Wert beibehalten.
297
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.7. DER SECHSTE ENTWURF: . . .
Das kann natürlich auch etwas weniger umfangreich geschrieben werden, indem man im Hauptpro-
gramm die Struktur eines Datensatzes festlegt, diese Struktur in der Funktion aendern global macht
und dann über die Felder dieser Struktur schleift:
def aendern():
global strukturAdr
print(’Diese Namen sind in der Liste! ’)
anzeigen(1)
aendNr = input(’Bitte Nummer des zu ändernden Namens eingeben: ’)
for attribut in strukturAdr:
print([Link](), ’ (alt): ’, namen[aendNr][attribut])
aenderung = input(’ neu (Enter für beibehalten): ’)
if aenderung != u’’:
namen[aendNr][attribut] = aenderung
def initialisiere():
global namen
nDat = ’[Link]’
try:
namenDatei = open(nDat, ’r’)
nDatLesen(namenDatei)
except IOError:
martin = {’vorname’:’Martin’, ’nachname’:’Schimmels’,’alter’:54}
ekki = {’vorname’:’Eckard’, ’nachname’:’Krauss’,’alter’:41}
namen = [martin,ekki]
298
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
Beim Beenden des Programms wird jetzt die Liste in eine Datei geschrieben. Sicherheitshalber wird
überprüft, ob sich die Datei zum Schreiben öffnen lässt und im Falle des Mißlingens wird das über eine
Ausnahme abgefangen. Ansonsten ist das Schreiben einer beliebigen Struktur einfach: pickle nimmt
die Struktur und schreibt sie per dump, so wie sie ist, in eine Datei.
299
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 class Adresse():
6 def __init__(self, vorname=’’, nachname=’’, alter=0):
7 if vorname == ’’ and nachname == ’’ and alter == 0:
8 [Link]()
9 else:
10 [Link] = vorname
11 [Link] = nachname
12 [Link] = alter
13
14 def anzeigen(self):
15 print([Link], ’ ’, [Link], ’ ’, [Link])
16
17 def vornameAendern(self):
18 aString = ’alter Vorname: ’+[Link]+ ’ neuer Vorname: ’
19 [Link] = input(aString)
20
21 def nachnameAendern(self):
22 aString = ’alter Nachname: ’+[Link]+’ neuer Nachname: ’
23 [Link] = input(aString)
24
25 def alterAendern(self):
26 aString = ’altes Alter: ’+str([Link])+’ neues Alter: ’
27 [Link] = input(aString)
28
29 def aendern(self):
30 auswahl = input( ’Was soll geändert werden? (V)orname,
31 (N)achname, (A)lter ’ )
32 menuAendern = {’V’: [Link], ’N’: [Link],
33 ’A’:[Link]}
34 menuAendern[auswahl]()
35
36 def anlegen(self):
37 print(’neuer Name wird aufgenommen!’)
38 [Link] = input(’Vorname: ’)
39 [Link] = input(’Nachname: ’)
40 [Link] = input(’Alter: ’)
41
300
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
Dazu benötigt man wieder ein Programm, das diese Klasse aufruft:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
12 du = Adresse()
13 [Link]()
14
301
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
2 class AdressBuch():
3 def __init__(self):
4 [Link] = True
5 [Link] = []
6 while [Link]:
7 [Link]()
8
9 def menu(self):
10 auswahl = input(’\n#### AUSWAHL ####\n
11 alle Namen anzeigen: Z\n
12 Namen einfügen: N\n
13 Namen löschen: L\n
14 Namen ändern: A\n
15 Ende: E\n
16 #### ....... ####\b\b\b\b\b\b\b\b\b\b\b\b’)
17 menuListe = {’N’:[Link], ’L’:[Link],
18 ’A’:[Link], ’E’:[Link], ’Z’:[Link]}
19 menuListe[auswahl]()
20
21 def einfuegen(self):
22 neuerName = Adresse()
23 [Link](neuerName)
24
25 def loeschen(self):
26 print(’Folgende Namen sind in der Liste: ’)
27 [Link]()
28 loeschNr = input(’Nummer des zu löschenden Datensatzes angeben: ’)
29 del [Link][loeschNr]
30 print("So sieht’s jetzt aus: ")
31 [Link]()
32
33 def aendern(self):
34 print(’Folgende Namen sind in der Liste: ’)
35 [Link]()
36 aendNr = input(’Nummer des zu ändernden Datensatzes angeben: ’)
37 [Link][aendNr].aendern()
38
39 def beenden(self):
40 [Link] = False
41
42 def anzeigen(self):
43 lfdNr = 0
44 print(’\n##### Namensliste #####’)
45 for einName in [Link]:
46 print(’##\t’,lfdNr,’\t’)
47 [Link]()
48 lfdNr += 1
49 print(’##### ----------- #####’)
50
302
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
Das Adressbuch selber wird durch das folgende aufrufende Programm realisiert:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
7 meineAdressen = AdressBuch()
8
Das soll wirklich alles sein? Wer es nicht glaubt, soll es halt einfach ausprobieren!!
303
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
Das wird wieder fast wortwörtlich aus dem fünften Entwurf übernommen:
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 import pickle
5 class Adresse():
6 def __init__(self, vorname=’’, nachname=’’, alter=0):
7 if vorname == ’’ and nachname == ’’ and alter == 0:
8 [Link]()
9 else:
10 [Link] = vorname
11 [Link] = nachname
12 [Link] = alter
13
14 def anzeigen(self):
15 print([Link], ’ ’, [Link], ’ ’, [Link])
16
17 def vornameAendern(self):
18 aString = ’alter Vorname: ’+[Link]+ ’ neuer Vorname: ’
19 [Link] = input(aString)
20
21 def nachnameAendern(self):
22 aString = ’alter Nachname: ’+[Link]+’ neuer Nachname: ’
23 [Link] = input(aString)
24
25 def alterAendern(self):
26 aString = ’altes Alter: ’+str([Link])+’ neues Alter: ’
27 [Link] = input(aString)
28
29 def aendern(self):
30 auswahl = input(’Was soll geändert werden?
31 (V)orname, (N)achname, (A)lter ’ )
32 menuAendern = {’V’: [Link],
33 ’N’: [Link],
34 ’A’: [Link]}
35 menuAendern[auswahl]()
36
37 def anlegen(self):
38 print(’neuer Name wird aufgenommen!’)
39 [Link] = input(’Vorname: ’)
40 [Link] = input(’Nachname: ’)
41 [Link] = input(’Alter: ’)
42
304
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
2 class AdressBuch():
3
4 def __init__(self):
5 [Link] = True
6
7 [Link] = ’[Link]’
8 try:
9 namenDatei = open([Link], ’r’)
10 [Link](namenDatei)
11 except IOError:
12 [Link] = []
13 while [Link]:
14 [Link]()
15
24 def menu(self):
25 auswahl = input(’\n#### AUSWAHL ####\n
26 alle Namen anzeigen: Z\n
27 Namen einfügen: N\n
28 Namen löschen: L\n
29 Namen ändern: A\n
30 Ende: E\n
31 #### ....... ####\b\b\b\b\b\b\b\b\b\b\b\b’)
32 menuListe = {’N’:[Link],
33 ’L’:[Link],
34 ’A’:[Link],
35 ’E’:[Link],
36 ’Z’:[Link]}
37 menuListe[auswahl]()
38
39 def einfuegen(self):
40 neuerName = Adresse()
41 [Link](neuerName)
42
43 def loeschen(self):
44 print(’Folgende Namen sind in der Liste: ’)
45 [Link]()
46 loeschNr = input(’Nummer des zu löschenden Datensatzes angeben: ’)
47 del [Link][loeschNr]
48 print("So sieht’s jetzt aus: ")
49 [Link]()
50
305
KAPITEL 17. UND NOCH EIN BEISPIEL: EIN . . . 17.8. JETZT WIRD ES OBJEKTORIENTIERT
2 def aendern(self):
3 print(’Folgende Namen sind in der Liste: ’)
4 [Link]()
5 aendNr = input(’Nummer des zu ändernden Datensatzes angeben: ’)
6 [Link][aendNr].aendern()
7
8 def beenden(self):
9 [Link] = False
10 try:
11 namenDatei = open([Link], ’w’)
12 except IOError:
13 print(’na so was’)
14 [Link]([Link], namenDatei)
15 [Link]()
16
17 def anzeigen(self):
18 lfdNr = 0
19 print(’\n##### Namensliste #####’)
20 for einName in [Link]:
21 print(’##\t’,lfdNr,’\t’)
22 [Link]()
23 lfdNr += 1
24 print(’##### ----------- #####’)
25
306
18. Immer noch das Adressbuch — nur
schöner
18.1. Das Adressbuch kommt in die Datenbank
Die permanente Speicherung der Daten in einer Datei mit Hilfe von pickle ist nicht der Weisheit letz-
ter Schluß. Das vorhergehende Beispiel wird daher so erweitert, dass die Adress-Daten jetzt in einer
Tabelle einer relationen Datenbank gespeichert werden. Der Open-Source-Standard für solch kleine An-
wendungen ist das DBMS“ mysql.
”
An der Klasse Adresse muss zuallererst eine Kleinigkeit geändert werden. Da die Daten in der Da-
tenbank einen Primärschlüssel haben sollten, wird in der Tabellenstruktur für die Adressen eine laufen-
de Nummer eingefügt. Diese laufende Nummer muss auch in der Klasse Adresse bearbeitet werden.
Zusätzlich wird, weil die beiden Klassen Adresse und Adressbuch in der selben Datei stehen, bereits
hier die MySQL-Bibliothek eingebunden.
307
KAPITEL 18. IMMER NOCH DAS . . . 18.1. DAS ADRESSBUCH KOMMT IN DIE . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 import MySQLdb
5 class Adresse():
6 def __init__(self, lfdnr = 0, vorname=’’, nachname=’’,
7 strasse = ’’, plz = ’’, ort = ’’):
8 if vorname == ’’ and nachname == ’’:
9 [Link]()
10 else:
11 [Link] = lfdnr
12 [Link] = vorname
13 [Link] = nachname
14 [Link] = strasse
15 [Link] = plz
16 [Link] = ort
17
18 def anzeigen(self):
19 print(’\n######## Nr. des Datensatzes: ’, [Link],
20 ’\n## ’,[Link], ’ ’, [Link],
21 ’\n## ’, [Link], ’\n## ’,
22 [Link], ’ ’, [Link], ’\n########’)
23
24 def vornameAendern(self):
25 print(’häää?? Vornamen ändern??’)
26 aString = ’alter Vorname: ’+[Link]+ ’ neuer Vorname: ’
27 [Link] = input(aString)
28
29 def nachnameAendern(self):
30 aString = ’alter Nachname: ’+[Link]+’ neuer Nachname: ’
31 [Link] = input(aString)
32
33 def strAendern(self):
34 aString = ’alte Strasse: ’+str([Link])+’ neue Strasse: ’
35 [Link] = input(aString)
36
37 def plzAendern(self):
38 aString = ’alte PLZ: ’+str([Link])+’ neue PLZ: ’
39 [Link] = input(aString)
40
41 def ortAendern(self):
42 aString = ’alter Ort: ’+str([Link])+’ neuer Ort: ’
43 [Link] = input(aString)
44
45 def aendern(self):
46 auswahl = input(’Was soll geändert werden?
47 (V)orname, (N)achname, (A)lter,
48 (S)trasse, (P)LZ, (O)rt ’ )
49 menuAendern = {’V’: [Link], ’N’: [Link],
50 ’S’: [Link], ’P’: [Link],
51 ’O’: [Link]}
52 menuAendern[auswahl]()
53
308
KAPITEL 18. IMMER NOCH DAS . . . 18.1. DAS ADRESSBUCH KOMMT IN DIE . . .
2 def anlegen(self):
3 print(’neuer Name wird aufgenommen!’)
4 [Link] = input(’Vorname: ’)
5 [Link] = input(’Nachname: ’)
6 [Link] = input(’Strasse: ’)
7 [Link] = input(’PLZ: ’)
8 [Link] = input(’Ort: ’)
9
Die Klasse AdressBuch ändert sich mehr. Im Konstruktor der Klasse wird weiterhin zuerst eine
leere Liste adrListe erzeugt, in der für den Fall, dass alle Datensätze gelesen werden sollen, diese
zwischengespeichert werden. Danach wird die Verbindung zum DBMS hergestellt und versucht, die
Datenbank test adr zu öffnen. Falls das nicht gelingt, wird diese Datenbank erstellt. In einem zweiten
Schritt wird dann versucht, die Tabelle namen zu lesen, im Falle des Mißlingens wird eine solche Tabelle
erstellt. Danach wird die Liste gefüllt (eventuell bleibt sie leer, falls in der Tabelle der Datenbank noch
keine Daten vorhanden sind). Im letzten Schritt des Konstruktors wird die Endlos-Schleife des Menus
aufgerufen. Außerdem wird hier am Ende jeder Transaktion die Liste geleert und neu aus der Datenbank
eingelesen.
2 class AdressBuch():
3
4 def __init__(self):
5 [Link] = True
6 [Link] = []
7 try:
8 [Link] = [Link](host=’localhost’, db=’test_adr’)
9 [Link] = [Link]()
10 except:
11 print(’Datenbank "test_ms" existiert noch nicht und wird angelegt’)
12 [Link] = [Link](host=’localhost’)
13 [Link] = [Link]()
14 [Link](’CREATE DATABASE test_adr’)
15 [Link](’use test_adr’)
16 try:
17 [Link](’SELECT COUNT(*) FROM namen’)
18 except:
19 [Link](’CREATE TABLE namen (
20 lfdnr INT NOT NULL AUTO_INCREMENT,
21 vorname VARCHAR(30),
22 nachname VARCHAR(30),
23 str VARCHAR(30),
24 plz CHAR(5),
25 ort VARCHAR(30),
26 PRIMARY KEY(lfdnr))’)
27 [Link]()
28 while [Link]:
29 [Link]()
30 [Link] = []
31 [Link]()
32
Die einzelnen Methoden der Klasse AdressBuch sehen denen aus dem vorigen Beispiel sehr ähnlich.
309
KAPITEL 18. IMMER NOCH DAS . . . 18.1. DAS ADRESSBUCH KOMMT IN DIE . . .
Es wird (fast) immer ein Query-String aufgebaut, der dann mit dem Befehl execute ausgeführt wird.
Bei der Methode aendern muss allerdings eine andere Logik verwendet werden: vor dem Ändern
wird der zu ändernde Datensatz in ein Objekt der Klasse Adresse eingelesen, dieses Objekt wird für
die Änderung an die Klasse Adresse weitergegeben, und das veränderte Objekt, das aus der Klasse
zurückkommt, wird in die Datenbank geschrieben. Da man nicht weiß, welches Attribut des Objekts
geändert wurde, wird einfach jedes Attribut geändert.
2 def nDatLesen(self):
3 [Link](’SELECT * FROM namen ORDER BY nachname, vorname’)
4 for (lfdnr, vn, nn, strasse, plz, ort) in [Link]():
5 geleseneAdr = Adresse(lfdnr, vn, nn, strasse, plz, ort)
6 [Link](geleseneAdr)
7
8 def menu(self):
9 auswahl = input(’\n#### AUSWAHL ####\n
10 alle Namen anzeigen: Z\n
11 Namen einfügen: N\n
12 Namen löschen: L\n
13 Namen ändern: A\n
14 Ende: E\n
15 #### ....... ####\b\b\b\b\b\b\b\b\b\b\b\b’)
16 menuListe = {’N’:[Link], ’L’:[Link],
17 ’A’:[Link], ’E’:[Link], ’Z’:[Link]}
18 menuListe[auswahl]()
19
20 def einfuegen(self):
21 neuerName = Adresse()
22 [Link](’INSERT INTO namen
23 (vorname, nachname, str, plz, ort)
24 VALUES(%s, %s, %s, %s, %s)’,
25 ([Link], [Link],
26 [Link], [Link],
27 [Link]))
28
29 def loeschen(self):
30 print(’Folgende Namen sind in der Liste: ’)
31 [Link]()
32 loeschNr = input(’Nummer des zu löschenden Datensatzes angeben: ’)
33 loeschBefehl = ’DELETE FROM namen WHERE lfdnr = ’+str(loeschNr)
34 [Link](loeschBefehl)
35
310
KAPITEL 18. IMMER NOCH DAS . . . 18.1. DAS ADRESSBUCH KOMMT IN DIE . . .
2 def aendern(self):
3 print(’Folgende Namen sind in der Liste: ’)
4 [Link]()
5 aendNr = input(’Nummer des zu ändernden Datensatzes angeben: ’)
6 vorleseBefehl = ’SELECT * FROM namen WHERE lfdnr = ’+str(aendNr)
7 [Link](vorleseBefehl)
8 for (lfdnr, vn, nn, strasse, plz, ort) in [Link]():
9 geleseneAdr = Adresse(lfdnr, vn, nn, strasse, plz, ort)
10
11 [Link]()
12 updBefehl = "UPDATE namen SET vorname = ’"+[Link]+"’,
13 nachname = ’"+[Link]+"’,
14 str = ’"+[Link]+"’,
15 plz = ’"+[Link]+"’,
16 ort =’"+[Link]+"’
17 WHERE lfdnr = "+str(aendNr)
18 [Link](updBefehl)
19
20 def beenden(self):
21 [Link] = False
22
23 def anzeigen(self):
24 lfdNr = 0
25 print(’\n##### Namensliste #####’)
26
311
19. Eine Ampel
19.1. Der Entwurf
The traffic lights they turn blue tomorrow
(Jimi Hendrix1 )
In meinem nächsten Beispiel soll eine funktionierende Ampel programmiert werden. Dabei soll die
in Deutschland übliche Reihenfolge der Ampelfarben angezeigt werden, d.h. rot -> rot-gelb -> grün ->
gelb -> rot. Starten wir also mit einem Modell in UML.
Betrachten wir zuerst die Attribute der Ampel. Eine Ampel hat also verschiedene Zustände: rot,
rot-gelb, grün, gelb, also ein Attribut zustand. Diese Zustände werden in zwei Dictionaries abge-
legt. Im ersten Dictionary wird den Zahlen 0 bis 3 jeweils einer der Zustände zugeordnet, und zwar
in der Reihenfolge, die oben angegeben wurde. Ferner wird ein zweites Dictionary angelegt, in dem
den Zuständen (in der beschreibenden Form rot, rot-gelb usw.) ein Tripel von Farben zugeordnet wird.
Die Farben werden der Übersichtlichkeit halber aus einem weiteren Dictionary genommen, in dem dem
Farbnamen der übliche numerische Wert in der RGB-Schreibweise zugeordnet wird. Das letzte Attribut
der Ampel ist der aktuelle Zustand.
Die Klasse Ampel hat nur zwei Methoden. Zum einen die Methode umschalten, die Modulo 3 durch
die numerischen Zustände wechselt, zum zweiten die Methode anzeigen, die genau das macht. Das
UML-Diagramm sieht also so aus:
313
KAPITEL 19. EINE AMPEL 19.2. DIE REALISIERUNG
2 #!/usr/bin/python
3
4 class Ampel():
5 def __init__(self):
6 [Link] = {0:’rot’, 1:’rot-gelb’, 2:’gruen’, 3:’gelb’}
7 [Link] = {’rot’:’#FF0000’, ’gelb’:’#FFFF00’,
8 ’gruen’:’#00FF00’, ’schwarz’:’#000000’}
9 [Link] = {
10 ’rot’:[[Link][’rot’], [Link][’schwarz’], [Link][’schwarz’]],
11 ’rot-gelb’:[[Link][’rot’], [Link][’gelb’], [Link][’schwarz’]],
12 ’gruen’:[[Link][’schwarz’], [Link][’schwarz’], [Link][’gruen’]],
13 ’gelb’:[[Link][’schwarz’], [Link][’gelb’], [Link][’schwarz’]]}
14 [Link] = 0
15
16 def umschalten(self):
17 # das eigentliche Umschalten. BEACHTE: hier wird mod(3) gerechnet
18 [Link] = ([Link] + 1)%len([Link])
19
20 def anzeigen(self):
21 print(’\n=========\nDie Ampel ist %s’ % [Link][[Link]])
22 print(’Farben: ’, [Link][[Link][[Link]]])
23
Das aufrufende Programm ist wieder sehr einfach. Hier wird eine Endlosschleife benutzt, um die
Ampel umzuschalten.
eingabe = ’12345’
meineAmpel = Ampel()
while eingabe != ’x’:
eingabe = input(’Umschalten!!! Ende mit x’)
[Link]()
[Link]()
314
KAPITEL 19. EINE AMPEL 19.4. EINE KREUZUNG HAT 4 AMPELN! . . .
2 #!/usr/bin/python
3
4 class Ampel():
5 def __init__(self, bezeichnung = ’Nord’):
6 [Link] = bezeichnung
7 [Link] = {0:’rot’, 1:’rot-gelb’, 2:’gruen’, 3:’gelb’}
8 [Link] = {’rot’:’#FF0000’, ’gelb’:’#FFFF00’,
9 ’gruen’:’#00FF00’, ’schwarz’:’#000000’}
10 [Link] = {
11 ’rot’:[[Link][’rot’], [Link][’schwarz’], [Link][’schwarz’]],
12 ’rot-gelb’:[[Link][’rot’], [Link][’gelb’], [Link][’schwarz’]],
13 ’gruen’:[[Link][’schwarz’], [Link][’schwarz’], [Link][’gruen’]],
14 ’gelb’:[[Link][’schwarz’], [Link][’gelb’], [Link][’schwarz’]]}
15 [Link] = [’oben’, ’mitte’, ’unten’]
16
17 def umschalten(self):
18 # aus Datei den aktuellen Zustand lesen
19 try:
20 [Link](’r’)
21 [Link] = int([Link]())
22 [Link]()
23 except:
24 [Link] = 0
25
34 def anzeigen(self):
35 print(’\n=========\nDie Ampel ist %s’ % [Link][[Link]])
36 print(’Farben: ’, [Link][[Link][[Link]]])
37
38 ### Datei-Operationen
39 def dateiOeffnen(self, modus):
40 dateiName = [Link]+’.dat’
41 [Link] = open(dateiName,modus)
42
43 def dateiSchreiben(self):
44 [Link](str([Link]))
45
46 def dateiSchliessen(self):
47 [Link]()
48
315
KAPITEL 19. EINE AMPEL 19.4. EINE KREUZUNG HAT 4 AMPELN! . . .
Aber natürlich sind nicht immer alle Lichter aller 4 Ampeln an. Die Regeln für die Ampeln sind aus
den folgenden 4 Zeichnungen zu entnehmen. Zuerst darf man von Nord nach Süd (und umgekehrt)
fahren.
316
KAPITEL 19. EINE AMPEL 19.5. DIE REALISIERUNG
Dann darf man von West nach Ost (und umgekehrt) fahren.
317
KAPITEL 19. EINE AMPEL 19.5. DIE REALISIERUNG
2 #!/usr/bin/python
3
6 class Kreuzung():
7 def __init__(self):
8 [Link] = [’Nord’, ’West’, ’Sued’, ’Ost’]
9
10 [Link] = Ampel(’Nord’)
11 [Link] = Ampel(’West’)
12 [Link] = Ampel(’Sued’)
13 [Link] = Ampel(’Ost’)
14 [Link] = [[Link], [Link], [Link], [Link]]
15
16 def umschalten(self):
17 for eineAmpel in [Link]:
18 [Link]()
19
Weiter hinten bei [Ampel im WWW], wenn Python als Sprache für dynamische Web-Seiten behandelt
wird, gibt es die Realisierung der Kreuzung als HTML-Seite mit einem Knopf zum Umschalten.
318
Teil X.
Grafik! Internet!
319
20. CGI-Programme
20.1. HTML und Kollegen
Hier soll keine Einführung in HTML gegeben werden. Eine gute Empfehlung im WWW für die, die
HTML lernen wollen, ist immer noch Self-HTML. 1
Auf den folgenden Seiten wird nur ein kurzer Abriss von HTML gegeben. Für die Programmierung
von dynamischen Seiten mit Python ist das aber ausreichend.
• Wenn man keine Vorstellung von der Struktur einer Seite hat, dann bewirkt die Benutzung eines
HTML-Editors meistens, dass eine damit erstellte Seite nicht sehr elegant aussieht.
• Die meisten HTML-Editoren hinken den Browsern hinterher! Nicht alles, was angezeigt werden
kann, beherrscht auch der Editor.
• Die Einbindung von dynamischen Web-Seiten erfordert Programmierung in einer Skript-Sprache;
spätestens hier muß man den HTML-Code zu Fuß“ eingeben.
”
• Auch die Erstellung einer HTML-Seite, die mit Werten aus einer Datenbank gefüllt wird, benötigt
HTML-Befehle.
20.2.2. Grundlagen
HTML-Code besteht aus dem Inhalt und den Auszeichnungen. Diese Auszeichnungen werden als tag“ be-
”
zeichnet. Ein HTML-Befehl umschließt einen Bereich und wird von einem Start-tag“ und einem Ende-
” ”
tag“ eingerahmt. Ein solcher Bereich wird auch Tag-Container“ genannt. HTML-tags können geschach-
”
telt werden. Start-tags sind in größer- und kleiner-Zeichen eingeschlossen. Ende-tags unterscheiden sich
von Start-tags dadurch, dass das erste Zeichen nach dem kleiner-Zeichen ein Schrägstrich ist. Beispiele
siehe nächstes Kapitel.
Einige tags können Attribute haben, die das Verhalten des tags ändern. Die wichtigsten Attribute
werden weiter unten im Kontext genannt.
321
KAPITEL 20. CGI-PROGRAMME 20.2. ALLGEMEINES ZU HTML
Beispiel 20.2.1
<HTML>
<HEAD>
<TITLE>
</TITLE>
</HEAD>
<BODY>
</BODY>
</HTML>
20.2.6. Hervorhebungen
Besondere Textstellen können auf verschiedene Art hervorgehoben werden:
Wenn man einen ganzen Absatz besonders darstellen will, bietet sich der <DIV>-Container an. Da-
mit wird ein beliebiges Stück Text zusammengefasst, dem man mittels diverser Attribute ein eigenes
Aussehen verpassen kann.
322
KAPITEL 20. CGI-PROGRAMME 20.2. ALLGEMEINES ZU HTML
20.2.7. Listen
1. Geordnete Listen. Geordnete Listen sind durch Numerierung der Listeneinträge gekennzeichnet;
das kann verschiedene Formen haben: 1., 2., 3., usw. oder a), b), c) usw. Geordnete Listen werden
in den <OL>-Container gepackt. Listenelemente werden in den <LI>-Container gepackt.
2. Ungeordnete Listen. Ungeordnete Listen werden durch Rauten, Rechtecke, etc. gekennzeichnet.
Ungeordnete Listen werden in den <UL>-Container gepackt. Listenelemente werden in den <LI>-
Container gepackt.
3. Definitionslisten. Definitionslisten werden haben einen zu definierenden Begriff und eine defi-
nierende Beschreibung. Definitionslisten werden in den <DL>-Container gepackt. Der zu defi-
nierende Begriff wird in den <DT>-Container gepackt. Die definierende Beschreibung wird in
den <DD>-Container gepackt.
20.2.8. Links
Ein Link ist eine Verknüpfung oder Verbindung zu einem anderen Textstück. Zu einem Link gehören
immer zwei Auszeichnungen: erstens die Adresse, zu der gesprungen werden soll, und zweitens der
Sprungbefehl.
1. Interne Links. Ein interner Link ist eine Verbindung zu einem Textstück im selben Dokument. Er
wird häufig benutzt, um auf einer Seite an den Anfang oder an das Ende zu springen.
• Die Adresse, zu der gesprungen werden soll, wird im <A NAME=Adresse>-Container ver-
packt.
• Der Sprungbefehl wird im <A HREF=#Adresse>-Container verpackt.
2. Externe Links. Ein externer Link ist eine Verbindung zu einem HTML-Dokument auf dem eigenen
oder einem entferneten Rechner.
• Die Adresse, zu der gesprungen werden soll, kann hier jede URL sein.
• Der Sprungbefehl wird im <A HREF=Adresse>-Container verpackt. (Der Unterschied zum
internen Link ist das Fehlen des ”Lattenzaunes”.)
20.2.9. Formulare
Ein Formular wird durch das tag-Paar <FORM> und </FORM> eingeschlossen. Dabei benötigt das
<FORM>-tag noch Attribute, damit überhaupt mit dem Formular gearbeitet werden kann. Vollständig
sieht das Attribut so aus: <FORM action= prozedurName“ method= XXX“>. Dabei steht prozedurName
” ”
für den Namen des Programms, das das Formular auswerten soll; XXX steht für die Art, wie die Feld-
inhalte des Formulars an das Programm weitergegeben werden. Es gibt die beiden Methoden GET und
POST. Auf die Unterschiede der beiden Methoden soll hier nicht weiter eingegangen werden. Die Me-
thode POST ist aber aus Sicherheitsgründen vorzuziehen.
Ein Formular muss natürlich neben Text auch noch Eingabefelder enthalten. Eingabefelder werden
durch das tag <INPUT> realisiert. Es gibt verschiedene Typen von Eingabefelder, von denen hier zwei
vorgestellt werden.
Auf jeden Fall sollte ein Formular einen Knopf enthalten, der das Absenden des Formulars bewirkt.
Das ist ein spezielles Eingabe-Feld, das durch den tag <INPUT type= submit“ name= absenden“>
” ”
erzeugt wird, wobei der Text des Attributs name natürlich frei gewählt werden kann. Der type mit
dem Wert submit erledigt das Absenden.
Die wahrscheinlich häufigste Art, in ein Formular Werte einzugeben, ist über ein Textfeld, in das man
mit der Tastatur Text oder Zahlen schreibt. Das geschieht mit dem tag <INPUT type= text“ name= a“
” ”
value= “>. Das Attribut mit dem Wert type=“text” gibt an, dass hier ein Texteingabefeld geöffnet wird.
”
Damit das weiterverarbeitende Programm auch weiß, welche Variable mit dem in diesem Eingabefeld
eingegebenen Wert belegt werden soll, muss dem Textfeld noch der Name einer Variablen angegeben
werden; dies geschieht durch das Attribut text=“ xxx” . Sofern man dem Texteingabefeld einen Startwert
(den man dann überschreiben kann) mitgeben will, wird der dem Attribut value=“ ” zugewiesen.
Da einem Eingabefeld in einem Formular ein Vortext vorangestellt werden sollte, damit der Benutzer
weiß, was er überhaupt eingeben sollte, sehen Formulare erst einmal zerfleddert aus. Das kann man
glätten, indem man das Formular in eine Tabelle einbettet.
323
KAPITEL 20. CGI-PROGRAMME 20.3. CGI (DAS COMMON GATEWAY . . .
3 <html>
4 <head>
5 <title>erste HTML-Seite</title>
6 </head>
7 <body>
8 <p>hello world</p>
9 </body>
10 </html>
11
12
So weit, so gut, aber das soll ja keine Anleitung für HTML sein, und das ist eine einfache HTML-Seite.
324
KAPITEL 20. CGI-PROGRAMME 20.5. HELLO WORLD ALS DYNAMISCHE . . .
Wichtig dabei ist, dass nach dem Header immer eine Zeile freigelassen werden muss. Die ganze dy-
namische Web-Seite wird jetzt folgendermaßen gebaut. Der gesamte HTML-Block von oben wird als
eine Zeichenkette, die sich über mehrere Zeilen erstreckt, in dreifache Anführungsstriche geschrieben
und an eine Variable zugewiesen.
3 seite = """
4 <html>
5 <head>
6 <title>erste HTML-Seite</title>
7 </head>
8 <body>
9 <p>hello world</p>
10 </body>
11 </html> """
12
13
seite = """
<html>
<head>
<title>erste HTML-Seite</title>
</head>
<body>
<p>hello world</p>
</body>
</html> """
print("Content-type: text/html\n")
print(seite)
Das war es schon! Leider ist es jetzt nicht für jeden sofort zu überprüfen, ob das auch wirklich wie
gewünscht funktioniert, denn nicht jeder hat einen Webserver auf seinem Rechner. Diejenigen, die unter
Linux arbeiten, haben wahrscheinlich schon den Apache installiert. Dann muss das oben geschriebene
Programm noch gespeichert werden (etwa unter dem Namen [Link]), und in das richtige Ver-
zeichnis verschoben werden, meistens /srv/www/cgi-bin. Jetzt muss man noch bedenken, dass ein
CGI-Skript ein Programm ist, das aufrufbar sein muss. Unter Unix / Linux wird also das Attribut auf
0755 gesetzt werden, und dann kann die Seite mit [Link] im Browser
aufgerufen werden.
Für diejenigen, die keinen Webserver eingerichtet haben, kommt im nächsten Kapitel ein Mini-Webserver,
der in Python geschrieben ist.
325
KAPITEL 20. CGI-PROGRAMME 20.6. EIN EIGENER MINI-WEBSERVER
Dieser Webserver ist übernommen aus M. Lutz, [Programming Python]. Wie Mark Lutz schreibt, erhebt
er keinen Anspruch auf Komfort und Sicherheit, aber er tut es, um auf seinem eigenen Rechner etwas
schnell zu testen. In der Zeile mit webdir = ’???’ müssen natürlich die Fragezeichen ersetzt werden
durch das Verzeichnis, in dem die CGI-Skripte gespeichert werden. Damit ist man aber auf der anderen
Seite unabhängig von den Standard-Vorgaben über die Speicherung von CGI-Skripten und kann diese
in einem beliebigen Verzeichnis (auch im eigenen home-Verzeichnis) speichern. In der darauffolgen-
den Zeile ist der Standard-Port für HTTP eingetragen, aber auch der kann geändert werden, falls das
benötigt oder gewünscht ist.
2 #!/usr/bin/python
3 import os, sys
4 from BaseHTTPServer import HTTPServer
5 from CGIHTTPServer import CGIHTTPRequestHandler
6
10 if [Link][:3] == ’win’:
11 CGIHTTPRequestHandler.have_popen2 = False
12 CGIHTTPRequestHandler.have_popen3 = False
13 [Link](’cgi-bin’)
14
15 [Link](webdir)
16 srvaddr = ("", port)
17 srvobj = HTTPServer(srvaddr, CGIHTTPRequestHandler)
18 srvobj.serve_forever()
19
So ein schön kurzes Programm, aber es reicht wirklich als Webserver für den Hausgebrauch.
In diesem Teil sollen jetzt erste dynamische Seiten erstellt werden. Dazu lassen wir zuerst einmal eine
Variable eine Schleife durchlaufen, vorwärts und rückwärts, und dann bringen wir das kleine Einmal-
eins auf eine HTML-Seite.
20.7.1. Vorwärtszählen ..
Wie im vorigen Beispiel wird zuerst der HTML-Code aufgebaut. Dieser wird in dreifache Anführungsstriche
geschrieben. An der Stelle, wo durch Python dynamischer Inhalt eingefügt werden soll, wird der Platz-
halter %s geschrieben.
326
KAPITEL 20. CGI-PROGRAMME 20.7. DYNAMIK DURCH SCHLEIFEN
#!/usr/bin/python
seite = ’’’
<html>
<head>
<title>FOR-Schleife</title>
</head>
<body>
%s
</body>
</html>’’’
for i in range(5):
text += zeile % i
print("Content-type: text/html\n\n")
print(seite % text)
In der letzten Zeile wird die Seite ausgegeben, wobei durch den Prozentoperator der Inhalt der Varia-
blen text in die Variable seite eingefügt wird.
Wie man sofort sieht, ändert sich nur eine Zeile, nämlich die Schleifenbedingung für das Zählen. Während
vorher nur ein Parameter an die Schleife mitgegeben wurde, nämlich das Ende der Schleife (das ist dort
oben bei 5), werden jetzt drei Parameter mitgegeben: der Start (6), das Ende (0) und die Schrittweite (-1).
Das ist alles.
327
KAPITEL 20. CGI-PROGRAMME 20.7. DYNAMIK DURCH SCHLEIFEN
#!/usr/bin/python
seite = ’’’
<html>
<head>
<title>FOR-DOWNTO-Schleife</title>
</head>
<body>
%s
</body>
</html>
’’’
zeile = "Ich bin eine FOR DOWNTO Schleife und bin gerade beim Zaehler %d<br/>"
text = ’’
print("Content-type: text/html\n\n")
print(seite % text)
Jetzt folgt als nächstes Beispiel eine HTML-Seite, die das kleine Einmaleins anzeigt. Hier ist es sinnvoll,
eine Funktion zu schreiben, die das erledigt. Im ersten Anlauf wird jeweils eine Zeile generiert, die Zeile
mit einem Zeilenvorschub beendet, und dann die nächste Zeile erstellt. Die einzelnen Zeilen werden
aneinandergehängt, und der erzeugte String wieder mit Hilfe der Formatierung von Zeichenketten in
den HTML-Code eingefügt.
328
KAPITEL 20. CGI-PROGRAMME 20.7. DYNAMIK DURCH SCHLEIFEN
#!/usr/bin/python
seite = ’’’
<html>
<head>
<title>Kleines 1 x 1</title>
</head>
<body>
%s
</body>
</html>
’’’
def klEinMalEins():
klEinMalEinsString = ’’ # eine leere Zeichenkette wird
# bereit gestellt
for z in range(1, 11):
for s in range(1, 11):
klEinMalEinsString += str(z*s) + ’ ’ # die nächste Zahl wird nach einem
# Leerzeichen eingefügt
klEinMalEinsString += ’<br/>’ # die Zeile wird mit einem
# Zeilenvorschub beendet
return klEinMalEinsString # die Zeichenkette wird zurück-
# gegeben
# Ende der Funktion
print(headerZeile) # Header ausgeben
Das funktioniert. Aber es sieht wirklich nicht schön aus, das muss man wohl zugeben.
Die Verbesserung ist, dass man das kleine Einmaleins jetzt in einer HTML-Tabelle ausgibt. Die Varia-
ble seite sieht fast genau so aus wie bisher, es sind nur die Tags für die Tabelle dazugekommen. Die
Funktion klEinMalEins hat sich etwas mehr geändert. Die Zeile, die jetzt generiert wird, beginnt und
329
KAPITEL 20. CGI-PROGRAMME 20.7. DYNAMIK DURCH SCHLEIFEN
endet mit den Tags für eine Tabellenzeile, jeder einzelne Eintrag bekommt die Table-Data-Tags, versehen
mit der Option rechtsbündig.
#!/usr/bin/python
seite = ’’’
<html>
<head>
<title>Kleines 1 x 1</title>
</head>
<body>
<table border=’1’>
%s
</table>
</body>
</html>
’’’
def klEinMalEins():
klEinMalEinsString = ’’
for z in range(1, 11):
klEinMalEinsString += ’<tr>’
for s in range(1, 11):
klEinMalEinsString += ’<td align="right">’+str(z*s)+ ’</td>’
klEinMalEinsString += ’</tr>’
return klEinMalEinsString
print(headerZeile)
print(seite % klEinMalEins())
330
KAPITEL 20. CGI-PROGRAMME 20.8. FORMULAR-EINGABE UND . . .
—Monty Python2
In diesem Abschnitt soll jetzt das Zusammenspiel von HTML-Formularen und auswertenden Python-
Programmen bearbeitet werden. Aus diesem Grund wird zuerst einmal ein HTML-Formular entworfen,
in das Vorname, Nachname und Betrieb des Benutzers eingegeben werden können.
3 <html>
4 <head>
5 <title>Eingabe</title>
6 </head>
7 <body>
8
13 Vorname:<br>
14 <input type="text" name="vorname"><br>
15 Nachname:<br>
16 <input type="text" name="nachname"><br>
17 Betrieb:<br>
18 <input type="text" name="betrieb"><br>
19 <br>
20
26 </form>
27 </body>
28 </html>
29
30
331
KAPITEL 20. CGI-PROGRAMME 20.8. FORMULAR-EINGABE UND . . .
Die HTML-Tags sollen hier im einzelnen nicht durchgesprochen werden. Erwähnenswert ist hier nur
die Zeile mit form action. Hier muss der Dateiname des Python-Skriptes angegeben werden, das die
Eingabe auswertet. Daten aus Formularen können mit 2 Methoden weitergegeben werden: mittels post
oder mittels get. Der wesentliche Unterschied ist der, dass die mit post geschickten Daten in einem
gesonderten Paket an den Server geschickt werden, während bei der Methode get die Daten an die
URL nach einem Fragezeichen angehängt werden. Das kann man nachher ganz schnell testen, wenn
das Formular und das zugehörige Programm erst einmal funktionieren.
332
KAPITEL 20. CGI-PROGRAMME 20.8. FORMULAR-EINGABE UND . . .
3 #!/usr/bin/python
4 # -*- coding: utf-8 -*-
5
6 import cgi
7 formularFelder = [Link]()
8
9 seite = ’’’
10 <html>
11 <head>
12 <title>Formularauswertung</title>
13 </head>
14 <body>
15 Auswertung eines Formulars
16 <br>
17 <br>
18 %s
19 </body>
20 </html>’’’
21
27 print("Content-type: text/html\n\n")
28 print(seite % zeilen)
29
Die wichtigen Zeilen sind die beiden ersten. Um Formulareingaben zu verarbeiten, muss die Biblio-
thek cgi eingebunden werden. Diese Bibliothek enthält die Klasse FieldStorage, die alle übergebenen
Daten enthält, egal wie sie übergeben wurden.
Danach wird wieder eine Seite in HTML aufgebaut, und diese wird in der Variablen seite gespei-
chert. Der von Python generierte dynamische Code beginnt mit der Zuweisung von Text an die Variable
zeilen. Danach wird mittels des Kurzschluss-Additions-Operators += Text angehängt, der aus den
übertragenen Daten aus dem Formular bestehen.
Die Klasse [Link] enthält die Daten in Form eines Dictionary. Das heißt im vorliegenden
Fall, dass die Variable formularFelder so aufgebaut ist:
formularFelder = {’vorname’:’Martin’, ’nachname’:’Schimmels’, ’betrieb’:’BMW’}
Es ist jetzt ganz einfach, die Methode get bei der Übertragung von Daten zu testen. Es muss nur in der
Zeile mit form action im HTML-Formular das post in ein get geändert werden. Das verarbeitende
333
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
Python-Programm muss nicht geändert werden, weil die Methoden des Moduls cgi die ganze Arbeit
erledigen. Das Modul erkennt, in welcher Form die Daten übermittelt werden und wertet alles richtig
aus. Den Unterschied sieht man aber in der Adresszeile des Browsers. Bei Benutzung der Post-Methode
sieht diese Zeile so aus:
[Link]
[Link]
&nachname=Schimmels&betrieb=BMW+Dingolfing
Im nächsten Beispiel soll eine Rechnung für den Eintritt in eine Sportveranstaltung geschrieben werden.
Es gibt einen Normaltarif, dazu allerdings Ermäßigungen für Kinder, Studenten und Senioren. In ein
HTML-Formular soll die Anzahl Erwachsener, die Anzahl Kinder, Senioren und Studenten eingegeben
werden. Ein Python-Programm berechnet den Rechnungsbetrag, der dann auf der nächsten HTML-Seite
ausgegeben wird.
Das Eingabeformular könnte so aussehen:
334
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
3 <html>
4
5 <head>
6 <title>Rechnung Eintritt Sport</title>
7 <meta name="generator" content="Bluefish 2.2.3" >
8 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
9 </head>
10 <body>
11 <h1>Eintrittskarten für Sportveranstaltung</h1>
12 <p>
13 <form action="./cgi-bin/FranksAufgaben/[Link]" method="POST">
14 <br>
15 <table>
16 <tr>
17 <td>Anzahl Erwachsene:</td>
18 <td><input type="text" name="erw"></td>
19 </tr>
20 <tr>
21 <td>Anzahl Kinder:</td>
22 <td><input type="text" name="kind"></td>
23 </tr>
24 <tr>
25 <td>Anzahl Senioren:</td>
26 <td><input type="text" name="sen"></td>
27 </tr>
28 <tr>
29 <td>Anzahl Studenten:</td>
30 <td><input type="text" name="stud"></td>
31 </tr>
32 </table>
33
39 </form>
40 </p>
41
42 </body>
43 </html>
44
45
Für die Berechnung des Rechnungsbetrags erstellen wir eine Klasse Rechnung. Der Konstruktor der
Klasse nimmt die Anzahl der Erwachsenen, Kinder, Senioren und Studenten in Empfang. Die Klasse hat
die Methode rechnungSchreiben, zusätzlich zum Testen auch noch die Methode rechnungAnzeigen.
Um den Test durchzuführen, wird wieder einmal mittels des Konstrukts if name == ’ main ’:
der Test in die Klassen-Datei eingefügt.
335
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
2 #!/usr/bin/python
3
4 class Rechnung():
5 def __init__(self, anzErw=0, anzKids=0, anzSen=0, anzStud=0):
6 [Link] = anzErw
7 [Link] = anzKids
8 [Link] = anzSen
9 [Link] = anzStud
10 [Link] = 10.0
11 [Link] = 0.5
12 [Link] = 0.3
13 [Link] = 0.4
14
15 def rechnungSchreiben(self):
16 [Link] = [Link] * [Link]
17 + [Link] * [Link]*[Link]
18 + [Link]*[Link]*[Link]
19 + [Link]*[Link]*[Link]
20
21 def rechnungAnzeigen(self):
22 print(’Rechnungsbetrag: ’+ str([Link]))
23
24 if __name__ == ’__main__’:
25 meineRechnung = Rechnung(3, 2, 4, 1)
26 [Link]()
27 [Link]()
28
336
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
Nachdem der Test erfolgreich war, wird das Skript, das die Auswertung durchführt, geschrieben. Das
sieht so aus:
3 #!/usr/bin/python
4
5 import cgi
6 formularFelder = [Link]()
7
8 seite = ’’’
9 <html>
10 <head>
11 <title>Rechnung Sportveranstaltung</title>
12 </head>
13 <body>
14 <h1>Rechnung</h1>
15 <br>
16 <br>
17 %s
18 </body>
19 </html>’’’
20
21
43 print("Content-type: text/html\n\n")
44
45 print(seite % str([Link]))
46
47
48
Zu beachten in diesem Stück Code sind die 4 try - except-Anweisungen. Damit wird gesichert,
dass das Skript auch dann korrekt arbeitet, wenn im Formular ein Feld nicht gefüllt wird. In diesem Fall
wird angenommen, dass für diese Gruppe Menschen der Wert 0“ gemeint ist.
”
337
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
Abbildung 20.3. Ausgabe einer Rechnung in HTML (aber wirklich nicht schön)
Da die Ausgabe des Programms wirklich nicht sehr schön ist, denn mit der alleinigen Angabe des zu
zahlenden Betrags kann man nicht zufrieden sein, wird die Klasse Rechnung verbessert. Die Veränderung
findet in der Methode rechnungSchreiben statt. Von der Logik ändert sich nichts, es handelt sich hier
nur um Änderungen in der Darstellung durch HTML. Die Ausgabe wird hier in eine Tabelle gemacht.
338
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
3 #!/usr/bin/python
4
5 class Rechnung():
6 def __init__(self, anzErw=0, anzKids=0, anzSen=0, anzStud=0):
7 [Link] = anzErw
8 [Link] = anzKids
9 [Link] = anzSen
10 [Link] = anzStud
11 [Link] = 10.0
12 [Link] = 0.5
13 [Link] = 0.3
14 [Link] = 0.4
15
16 def rechnungSchreiben(self):
17 [Link] = [Link] * [Link]
18 + [Link] * [Link]*[Link]
19 + [Link]*[Link]*[Link]
20 + [Link]*[Link]*[Link]
21 [Link] = ’<table border="1">’
22 # Zeile f. Erwachsene
23 [Link] += ’<tr>’
24 [Link] += ’<td>Erwachsene:</td>
25 <td align="right">’+str([Link])+’</td>’
26 t1 = ’%4.2f’ % [Link]
27 [Link] += ’<td align="right">’+str(t1)+’ Euro</td>’
28 t2 = ’%4.2f’ % ([Link] * [Link])
29 [Link] += ’<td align="right">’+str(t2)+’ Euro</td>’
30 [Link] += ’</tr>’
31 # Zeile f. Kinder
32 [Link] += ’<tr>’
33 [Link] += ’<td>Kinder:</td>
34 <td align="right">’+str([Link])+’</td>’
35 t1 = ’%4.2f’ % ([Link] * [Link])
36 [Link] += ’<td align="right">’+str(t1)+’ Euro</td>’
37 t2 = ’%4.2f’ % ([Link] * [Link] * [Link])
38 [Link] += ’<td align="right">’+str(t2)+’ Euro</td>’
39 [Link] += ’</tr>’
40
41
339
KAPITEL 20. CGI-PROGRAMME 20.9. EINE RECHNUNG
3 # Zeile f. Senioren
4 [Link] += ’<tr>’
5 [Link] += ’<td>Senioren:</td>
6 <td align="right">’+str([Link])+’</td>’
7 t1 = ’%4.2f’ % ([Link] * [Link])
8 [Link] += ’<td align="right">’+str(t1)+’ Euro</td>’
9 t2 = ’%4.2f’ % ([Link] * [Link] * [Link])
10 [Link] += ’<td align="right">’+str(t2)+’ Euro</td>’
11 [Link] += ’</tr>’
12 # Zeile f. Studis
13 [Link] += ’<tr>’
14 [Link] += ’<td>Studenten:</td>
15 <td align="right">’+str([Link])+’</td>’
16 t1 = ’%4.2f’ % ([Link] * [Link])
17 [Link] += ’<td align="right">’+str(t1)+’ Euro</td>’
18 t2 = ’%4.2f’ % ([Link] * [Link] * [Link])
19 [Link] += ’<td align="right">’+str(t2)+’ Euro</td>’
20 [Link] += ’</tr>’
21 # Summen-Zeile
22 [Link] += ’<tr> <td colspan="3">Summe:</td> <td>’
23 t1 = ’%4.2f’ % ([Link])
24 [Link] += str(t1)+’ Euro’+ ’</td> </tr>’
25 # Ende
26 [Link] += ’</table>’
27
28 def rechnungAnzeigen(self):
29 print(’Rechnungsbetrag: ’+ str([Link]))
30
31 if __name__ == ’__main__’:
32 meineRechnung = Rechnung(3, 2, 4, 1)
33 [Link]()
34 [Link]()
35 print([Link])
36
37
In dem CGI-Skript muss dann nur die letzte Zeile ersetzt werden durch
340
KAPITEL 20. CGI-PROGRAMME 20.10. JETZT ABER WIRKLICHE DYNAMIK
Abbildung 20.4. Ausgabe einer Rechnung in HTML (so kann man das akzeptieren)
341
KAPITEL 20. CGI-PROGRAMME 20.10. JETZT ABER WIRKLICHE DYNAMIK
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 class Zaehler(object):
5 def __init__(self):
6 [Link](’r’)
7 [Link] = int([Link]())
8 [Link] = 0
9 [Link]()
10
17 def dateiSchliessen(self):
18 [Link]()
19
20 def wertZuruecksetzen(self):
21 [Link](’w’)
22 [Link] = [Link]
23 [Link]([Link])
24 [Link]()
25
26 def inkrement(self):
27 [Link](’w’)
28 [Link] = [Link] + 1
29 [Link]([Link])
30 [Link]()
31
32 def dekrement(self):
33 [Link](’w’)
34 [Link] = [Link] - 1
35 [Link]([Link])
36 [Link]()
37
Man kann sich natürlich jetzt ein kleines Programm schreiben, das diese Klasse benützt – und das
sollte man auch tun, um zu testen, ob alles so funktioniert, wie man sich das vorstellt.
Wenn man das gemacht hat und sicher ist, dass alles wie gewünscht tut, schreibt man sich die HTML-
Seite, die den Besucherzähler aufnehmen soll. An der Stelle, wo der Besucherzähler nachher tatsächlich
arbeiten soll, stehen im Moment noch 3 Fragezeichen.
342
KAPITEL 20. CGI-PROGRAMME 20.10. JETZT ABER WIRKLICHE DYNAMIK
3 <html>
4 <head>
5 <title>Martins Test</title>
6 <meta http-equiv="Content-type" content="text/html; charset=latin1" />
7 </head>
8 <body>
9 <h1>Ein Besucherzähler</h1>
10 <p>Hallo Du da!!</p>
11 <p>Du bist der ???. Besucher</p>
12 </body>
13 </html>
14
15
Diese ganzer HTML-Code wird, wie schon weiter oben, in dreifache Anführungszeichen gesetzt. Statt
der 3 Fragezeichen wird jetzt ein Python-Platzhalter, das
%s
, geschrieben. Die Header-Zeile wird geschrieben und es wird die Klasse Zaehler importiert. Eine
Instanz von Zaehler wird erzeugt und der Wert erhöht. Dann wird die vorher in Anführungszeichen
geschriebene Seite geschrieben, wobei der aktuelle Wert des Zählers über die String-Ersetzung des
%s
vorgenommen wird. (Falls Du nicht mehr weißt, wie das mit der Formatierung funktioniert, hier ist der
Link zu dieser Seite.)
3 #!/usr/bin/python
4
5 seite = ’’’
6 <html>
7 <head>
8 <title>Martins Test</title>
9 <meta http-equiv="Content-type" content="text/html; charset=latin1" />
10 </head>
11 <body>
12 <h1>Ein Besucherzähler</h1>
13 <p>Hallo Du da!!</p>
14 <p>Du bist der %s . Besucher</p>
15 </body>
16 </html>
17 ’’’
18
19 print("Content-type: text/html\n\n")
20
25 print(seite % [Link])
26
27
343
21. Eine Kreuzung auf meiner Web-Seite
21.1. Die Ampel kommt ins Netz
Weiter oben bei [Ampel auf der Konsole] haben wir eine Ampel und eine Kreuzung realisiert. Nun soll
daraus eine dynamische WEeb-Seite werden. In einem ersten Schritt erstellen wir eine statische Web-
Seite, die in einer Tabelle die Ampel darstellt. Der HTML-Code dazu sieht so aus:
3 <html>
4 <head>
5 <title>Eine Ampel</title>
6 <meta name="generator" content="Bluefish 2.2.3" />
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
8 </head>
9 <body bgcolor="#C6C6C6">
10 <h1>Eine Ampel</h1>
11 <table width="120" cellspacing="10" border="10" cellpadding="10"
12 align="center" bgcolor="white">
13 <tbody>
14 <tr>
15 <td></td>
16 </tr>
17 <tr>
18 <td></td>
19 </tr>
20 <tr>
21 <td></td>
22 </tr>
23 </tbody>
24 </table>
25 </body>
26 </html>
27
345
KAPITEL 21. EINE KREUZUNG AUF . . . 21.1. DIE AMPEL KOMMT INS NETZ
Der HTML-Code wird jetzt in eine Variable seite eingebunden. In den 3 Lichtern der Ampel wird als
Attribut die Hintergrundfarbe eingefügt, wobei der Wert der Hintergrundfarbe über den %s-Operator
durch den folgenden Python-Code eingefügt wird. (Das kleine o im Tabellen-Element dient dazu, die
Ampel etwas größer zu machen.)
Der Python-Code bindet zuerst die Klasse Ampel ein, sodann wird ein Objekt dieser Klasse erzeugt
und die Methode umschalten dieses Objekts aufgerufen. Nachdem die Lichter der Ampel umgeschal-
tet wurden, werden die Farben der Lichter in einen Tupel geschrieben, der mit dem %-Operator in die
Variable seite eingefügt wird.
346
KAPITEL 21. EINE KREUZUNG AUF . . . 21.1. DIE AMPEL KOMMT INS NETZ
Beispiel 21.1.2
1
3 #!/usr/bin/python
4
5 seite = ’’’
6 <html>
7 <head>
8 <title>Eine Ampel</title>
9 </head>
10 <body bgcolor="#C6C6C6">
11 <h1>Eine Ampel</h1>
12 <table width="120" cellspacing="10" border="10" cellpadding="10"
13 align="center" bgcolor="white">
14 <tbody>
15 <tr>
16 <td bgcolor="%s">o</td>
17 </tr>
18 <tr>
19 <td bgcolor="%s">o</td>
20 </tr>
21 <tr>
22 <td bgcolor="%s">o</td>
23 </tr>
24 </tbody>
25 </table>
26 <FORM action="[Link]" method="POST">
27 <INPUT type="submit" name="umschalten" value="Umschalten" size="120">
28 </FORM>
29 </body>
30 </html>
31 ’’’
32
35 meineAmpel = Ampel()
36 [Link]()
37
40 print(headerZeile)
41 print(seite %
42 tuple([Link][[Link][[Link]]]))
43
44
347
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
Die Kreuzung ist eine 3x3 - Tabelle, bei der in die mittleren Zellen der äußeren Zeilen und Spalten jeweils
eine 3x1 - Tabelle die Ampel abbildet.
3 <html>
4 <head>
5 <title>Eine Ampel</title>
6 <meta name="generator" content="Bluefish 2.2.3" >
7 <meta http-equiv="Content-Type" content="text/html">
8 </head>
9 <body bgcolor="#C6C6C6">
10 <h1>Eine Kreuzung</h1>
11 <table width="720" cellspacing="10" border="10" cellpadding="10"
12 align="center" bgcolor="white">
13 <tr>
14 <td></td>
15 <td>
16 <table width="120" cellspacing="10" border="10" cellpadding="10"
17 align="center" bgcolor="white">
18 <tbody>
19 <tr>
20 <td bgcolor="#FF0000"></td>
21 </tr>
22 <tr>
23 <td bgcolor="#000000"></td>
24 </tr>
25 <tr>
26 <td bgcolor="#000000"></td>
27 </tr>
28 </tbody>
29 </table>
30 </td>
31 <td></td>
32 </tr>
33 <tr>
34 <td>
35 <table width="120" cellspacing="10" border="10" cellpadding="10"
36 align="center" bgcolor="white">
37 <tbody>
38 <tr>
39 <td bgcolor="#FF0000"></td>
40 </tr>
41 <tr>
42 <td bgcolor="#000000"></td>
43 </tr>
44 <tr>
45 <td bgcolor="#000000"></td>
46 </tr>
47 </tbody>
48 </table>
49 </td>
50
348
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
3 <td></td>
4 <td>
5 <table width="120" cellspacing="10" border="10" cellpadding="10"
6 align="center" bgcolor="white">
7 <tbody>
8 <tr>
9 <td bgcolor="#FF0000"></td>
10 </tr>
11 <tr>
12 <td bgcolor="#000000"></td>
13 </tr>
14 <tr>
15 <td bgcolor="#000000"></td>
16 </tr>
17 </tbody>
18 </table>
19 </td>
20 </tr>
21 <tr>
22 <td></td>
23 <td>
24 <table width="120" cellspacing="10" border="10" cellpadding="10"
25 align="center" bgcolor="white">
26 <tbody>
27 <tr>
28 <td bgcolor="#FF0000"></td>
29 </tr>
30 <tr>
31 <td bgcolor="#000000"></td>
32 </tr>
33 <tr>
34 <td bgcolor="#000000"></td>
35 </tr>
36 </tbody>
37 </table>
38 </td>
39 <td></td>
40 </tr>
41 </table>
42
349
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
Der Code für die dynamische Web-Seite ist nach dem selben Schema gebaut wie der Code für die
dynamische Web-Ampel. Der HTML-Code wird in die Variable seite eingebunden. In den 3 Lichtern
der 4 Ampeln wird als Attribut die Hintergrundfarbe eingefügt, wobei der Wert der Hintergrundfarbe
über den %s-Operator durch den folgenden Python-Code eingefügt wird. (Das kleine o im Tabellen-
Element dient dazu, die Ampel etwas größer zu machen.)
Der Python-Code bindet zuerst die Klasse clKreuzung ein, sodann wird ein Objekt dieser Klasse
erzeugt und die Methode umschalten dieses Objekts aufgerufen. Nachdem die Lichter der Ampel
umgeschaltet wurden, wird ein Tupel aufgebaut, der von allen 4 Ampeln die Farben der einzelnen
Lichter enthält, insgesamt also 12 Werte. Das ist der einzige etwas lästige Schritt in diesem Programm.
Denn diese 12 Werte werden zuerst in eine Liste, die zustandsListe, geschrieben, die dann beim
Einfügen in die seite in ein Tupel umgewandelt wird.
350
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
4 #!/usr/bin/python
5
6 seite = ’’’
7 <html>
8 <head>
9 <title>Eine Kreuzung</title>
10 </head>
11 <body bgcolor="#C6C6C6">
12 <h1>Eine Kreuzung</h1>
13 <table width="720" cellspacing="10" border="10" cellpadding="10"
14 align="center" bgcolor="white">
15 <tbody>
16 <tr>
17 <td></td>
18 <td>
19 <table width="120" cellspacing="10" border="10" cellpadding="10"
20 align="center" bgcolor="white">
21 <tbody>
22 <tr>
23 <td bgcolor="%s">o</td>
24 </tr>
25 <tr>
26 <td bgcolor="%s">o</td>
27 </tr>
28 <tr>
29 <td bgcolor="%s">o</td>
30 </tr>
31 </tbody>
32 </table>
33 </td>
34 <td></td>
35 </tr>
36 <tr>
37 <td>
38 <table width="120" cellspacing="10" border="10" cellpadding="10"
39 align="center" bgcolor="white">
40 <tbody>
41 <tr>
42 <td bgcolor="%s">o</td>
43 </tr>
44 <tr>
45 <td bgcolor="%s">o</td>
46 </tr>
47 <tr>
48 <td bgcolor="%s">o</td>
49 </tr>
50 </tbody>
51 </table>
52 </td>
53
351
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
3 <td></td>
4 <td>
5 <table width="120" cellspacing="10" border="10" cellpadding="10"
6 align="center" bgcolor="white">
7 <tbody>
8 <tr>
9 <td bgcolor="%s">o</td>
10 </tr>
11 <tr>
12 <td bgcolor="%s">o</td>
13 </tr>
14 <tr>
15 <td bgcolor="%s">o</td>
16 </tr>
17 </tbody>
18 </table>
19 </td>
20 </tr>
21 <tr>
22 <td></td>
23 <td>
24 <table width="120" cellspacing="10" border="10" cellpadding="10"
25 align="center" bgcolor="white">
26 <tbody>
27 <tr>
28 <td bgcolor="%s">o</td>
29 </tr>
30 <tr>
31 <td bgcolor="%s">o</td>
32 </tr>
33 <tr>
34 <td bgcolor="%s">o</td>
35 </tr>
36 </tbody>
37 </table>
38 </td>
39 <td></td>
40 </tr>
41 </tbody>
42 </table>
43
44
52
352
KAPITEL 21. EINE KREUZUNG AUF . . . 21.2. DIE KREUZUNG IM NETZ IST AUCH . . .
6 meineKreuzung = Kreuzung()
7 [Link]()
8
9 zustandsListe = []
10 for einZustand in [Link]
11 [[Link][[Link]]]:
12 [Link](einZustand)
13 for einZustand in [Link]
14 [[Link][[Link]]]:
15 [Link](einZustand)
16 for einZustand in [Link]
17 [[Link][[Link]]]:
18 [Link](einZustand)
19 for einZustand in [Link]
20 [[Link][[Link]]]:
21 [Link](einZustand)
22 #print(zustandsListe)
23 headerZeile = "Content-type: text/html\n\n"
24
25 print(headerZeile)
26
27 print(seite % tuple(zustandsListe))
28
353
22. Programme mit grafischer Oberfläche
The empty handed painter from your streets
Is drawing crazy patterns on your sheets
(Bob Dylan1 )
22.1. Tkinter
Das Toolkit von J. Ousterhout, abgekürzt ganz einfach tk“, hat eine Schnittstelle für Python, die sich
”
tkinter“ nennt. Die Benutzung dieses Toolkits macht deutlich, dass grundsätzlich bei einem Programm
”
unterschieden werden muss zwischen dem Teil, der das gegebene Problem löst, und dem Teil, der die
Lösung in einer dem Benutzer angenehmen Form präsentiert.
Vor allem Anfänger neigen dazu, das Design einer Schnittstelle zwischen Problemlösung und Be-
nutzer vorrangig zu bearbeiten, weil sich jeder, auch ein Programmieranfänger, zutraut, mit grafischen
Tools eine grafische Oberfläche zu erstellen. Weil dies hier aber ein Programmierkurs ist, wurde das De-
sign, die Benutzerfreundlichkeit, die Bedienbarkeit eines Programms bisher nicht in Angriff genommen.
Den wichtigsten Vorteil von tk (und damit von Tkinter) will ich hier aber auch nicht verschweigen:
auch tk“ ist freie Software und kann aus dem Internet heruntergeladen werden. In den meisten Python-
”
Distributionen ist Tkinter allerdings sogar eingebaut.
Hier soll keine Einführung in Tkinter gegeben werden, sondern nur an einem Beispiel gezeigt werden,
wie die verschiedenen Komponenten zusammenspielen. Es soll ein kleiner Umrechner für Temperatu-
ren (Celsius nach Fahrenheit und umgekehrt) geschrieben werden.
Dazu wird zuerst eine angemessene Klasse erzeugt:
1 It’s all over now, Baby Blue auf: Bringing it all back home
355
KAPITEL 22. PROGRAMME MIT . . . 22.2. PROBLEM: TEMPERATUREN . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4
5 class Temperatur():
6 def __init__(self):
7 [Link] = 0.001
8 [Link] = 0.002
9
10 def leseCelsius(self):
11 [Link] = float(input("Temperatur in Grad Celsius eingeben: "))
12
13 def leseFahrenheit(self):
14 [Link] = float(input("Temperatur in Grad Fahrenheit eingeben: "))
15
16 def celsius2fahrenheit(self):
17 [Link] = 9.0 / 5.0 * [Link] + 32.0
18
19 def schreibeFahrenheit(self):
20 print("Temperatur in Grad Fahrenheit: ",[Link])
21
22 def fahrenheit2celsius(self):
23 [Link] = 5.0 / 9.0 * ([Link] - 32)
24
25 def schreibeCelsius(self):
26 print("Temperatur in Grad Celsius: ",[Link])
27
28 def wertZuruecksetzen(self):
29 [Link] = 0.01
30 [Link] = 0.02
31
Wie immer gehört dazu ein aufrufendes Programm, das wieder einmal in einer While-Schleife Einga-
ben ermöglicht und dann diese bearbeitet.
356
KAPITEL 22. PROGRAMME MIT . . . 22.3. . . . UND JETZT MIT GRAFISCHER . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from cl_Temperatur import Temperatur
5
6 modus = ’x’
7 t1 = temperatur()
8 while modus != ’E’:
9 modus = input(’\nAuswahl: \nCelsius nach Fahrenheit mit C\n
10 Fahrenheit nach Celsius mit F\nEnde mit E: ’)
11 if modus == ’C’:
12 [Link]()
13 t1.celsius2fahrenheit()
14 [Link]()
15 elif modus == ’F’:
16 [Link]()
17 t1.fahrenheit2celsius()
18 [Link]()
19 elif modus == ’E’:
20 pass
21 else:
22 print(’Falsche Eingabe. Nur C, F, E erlaubt’)
23
24 print(’Ciao’)
25
Der Konstruktor der grafischen Oberfläche erstellt das Objekt und ruft die Methode erstelleWidgets
auf, die dann für die Elemente der Oberfläche zuständig ist. Diese Elemente werden in tk widgets ge-
nannt. Jedes widget ist ein Objekt einer Tkinter-Klasse, so ist zum Beispiel das widget b1 ein Objekt
der Klasse Button. Die Methode grid gibt an, wieviel Platz das Objekt im Gitter haben soll. Mit den
Methoden insert und delete werden Texte in die Entry-Objekte geschrieben. Den Buttons b1 und
b2 werden die Arbeits-Methoden, nämlich die Methoden, die die Umrechnung leisten, zugeordnet.
Diese Methoden der Oberfläche rufen natürlich nur die Methoden der Klasse Temperatur auf.
357
KAPITEL 22. PROGRAMME MIT . . . 22.3. . . . UND JETZT MIT GRAFISCHER . . .
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 from Tkinter import *
5 from Tkconstants import *
6 from cl_Temperatur import temperatur
7 import tkMessageBox
8
9 t1 = temperatur()
10
11 class App(Frame):
12 def __init__(self, master = None):
13 Frame.__init__(self, master)
14 [Link](’Temperatur-Rechner’)
15 [Link](padx = 10, pady = 10)
16 [Link]()
17
18 def erstelleWidgets(self):
19 [Link] = Button(self, text="Ende", bg="#C1281F", command=[Link])
20 [Link](row = 1, column = 4, columnspan = 1)
21
48 def rueckWert(self):
49 [Link]()
50 [Link](0, END)
51 [Link](0,[Link])
52 [Link](0, END)
53 [Link](0,[Link])
54
55 def meldeFenster(self):
56 if [Link](’Quit’, ’Wirklich aufhören?’):
57 k = self.winfo_toplevel()
58 [Link]()
59
358
KAPITEL 22. PROGRAMME MIT . . . 22.3. . . . UND JETZT MIT GRAFISCHER . . .
2 def CnachF(self):
3 [Link] = float([Link]())
4 t1.celsius2fahrenheit()
5 [Link](0, END)
6 [Link](0,[Link])
7
8 def FnachC(self):
9 [Link] = float([Link]())
10 t1.fahrenheit2celsius()
11 [Link](0, END)
12 [Link](0,[Link])
13
Das eigentliche Programm, das aufgerufen wird, ist folglich wieder sehr kurz. Es konstruiert nur
ein Objekt der gerade definierten Klasse der grafischen Oberlfläche und verschwindet in einer Endlos-
Schleife. Diese wird über den Ende-Button verlassen. That’s it!
def callback():
if [Link](’Quit’, ’Wirklich aufhören?’):
[Link]()
if __name__ == "__main__":
root = Tk()
meineTemp = App(root)
[Link](’WM_DELETE_WINDOW’, callback)
[Link]()
Eine nette Kleinigkeit wurde noch eingebaut: ein Zusatzrahmen öffnet sich, wenn man das Programm
beenden will. Dort wird man gefragt, ob man wirklich aufhören will (es geht auch ohne, und dann ist
das Hauptprogramm nochmal 4 Zeilen kürzer).
Das aufgerufene Programm präsentiert sich so:
Und das oben erwähnte Zusatzfenster, mit dem man das Programm endgültig beendet, erscheint so:
359
KAPITEL 22. PROGRAMME MIT . . . 22.3. . . . UND JETZT MIT GRAFISCHER . . .
360
Teil XI.
361
23. Python als Sprache für den eigenen
Rechner
23.1. Das Betriebssystem
Für die Arbeit mit dem eigenen Rechner ist Python auch sehr gut geeignet. Man erinnere sich: Batteries
included! Es gibt für alle Betriebssysteme Bibliotheken, die Aufrufe an das Betriebssystem erleichtern.
Das erste Modul ist das sys. Rein ins Vergnügen!
Also gehen wir auf die Python-Shell oder in eine IDE unserer Wahl und geben die Befehle import sys
gefolgt von dir(sys) ein. Jede Menge Informationen können vom Modul sys geliefert werden. Probieren
wir es also aus:
Hier wurde das Betriebssystem, die Versionsnummer von Python und die Copyrights für Python
ausgegeben.
Das ist hilfreich, wenn man ein Programm schreibt, von dem man vermutet, dass es auf verschiedenen
Rechnern unter verschiedenen Betriebssystemen laufen soll.
363
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.2. VERZEICHNISSE UND DATEIEN
Nicht schlecht. Aber seit einem der vorigen Kapitel wissen wir, dass durchaus noch mehr Informatio-
nen über einen Modul abgefragt werden können, nämlich mit help(sys). Eine Inhaltsangabe des Moduls
sys erhält man durch
2 >>> dir(sys)
3 [’__displayhook__’, ’__doc__’, ’__egginsert’, ’__excepthook__’,
4 ’__interactivehook__’, ’__loader__’, ’__name__’, ’__package__’, ’__plen’,
5 ’__spec__’, ’__stderr__’, ’__stdin__’, ’__stdout__’, ’_clear_type_cache’,
6 ’_current_frames’, ’_debugmallocstats’, ’_getframe’, ’_home’, ’_mercurial’,
7 ’_xoptions’, ’abiflags’, ’api_version’, ’arch’, ’argv’, ’base_exec_prefix’,
8 ’base_prefix’, ’builtin_module_names’, ’byteorder’, ’call_tracing’,
9 ’callstats’, ’copyright’, ’displayhook’, ’dont_write_bytecode’,
10 ’exc_info’, ’excepthook’, ’exec_prefix’, ’executable’, ’exit’, ’flags’,
11 ’float_info’, ’float_repr_style’, ’getallocatedblocks’, ’getcheckinterval’,
12 ’getdefaultencoding’, ’getdlopenflags’, ’getfilesystemencoding’, ’getprofile’,
13 ’getrecursionlimit’, ’getrefcount’, ’getsizeof’, ’getswitchinterval’,
14 ’gettrace’, ’hash_info’, ’hexversion’, ’implementation’, ’int_info’,
15 ’intern’, ’last_traceback’, ’last_type’, ’last_value’, ’lib’, ’maxsize’,
16 ’maxunicode’, ’meta_path’, ’modules’, ’path’, ’path_hooks’,
17 ’path_importer_cache’, ’platform’, ’prefix’, ’setcheckinterval’,
18 ’setdlopenflags’, ’setprofile’, ’setrecursionlimit’, ’setswitchinterval’,
19 ’settrace’, ’stderr’, ’stdin’, ’stdout’, ’thread_info’, ’version’,
20 ’version_info’, ’warnoptions’]
21
Beim Öffnen musste man bereits angeben, was man mit der Datei machen will: Lesen oder Schreiben.
Python hat sich seit den Anfängen enorm weiterentwickelt, und deswegen gibt es in Python jetzt
Iteratoren“, das heißt Methoden, die über eine Datei schleifen. Das erleichtert die Arbeit mit Dateien.
”
Dabei wird eine Datei als eine Liste von Zeilen gesehen, die man mit einer for-Schleife abarbeiten kann.
Python verwaltet die Struktur selbständig.
Die einfachste Möglichkeit ist dabei,
364
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.2. VERZEICHNISSE UND DATEIEN
Python stellt aber noch weitere Iteratoren zur Verfügung. Mit readline wird eine Zeile nach der an-
deren gelesen. Am Ende der Datei wird von der Methode readline eine leere Zeichenkette zurückgegeben.
Das ist für die Weiterverarbeitung unter Umständen ein kleines Problem, aber es funktioniert.
>>> [Link]()
Als letzte Möglichkeit gibt es noch den Iterator next. Der arbeitet sehr ähnlich wie readline, der
Unterschied ist, dass am Dateiende eine Exception auftritt.
Hier sieht man in den letzten Zeilen, dass Python am Dateiende auf einen Fehler läuft.
365
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.2. VERZEICHNISSE UND DATEIEN
Das zweite Modul, das mit dem Betriebssystem interagiert, ist das Modul os. Dieses Modul enthält für
fast alle gängigen Betriebssysteme Systemaufrufe, so dass Skripte, die dieses Modul benutzen, oft un-
verändert auf verschiedenen Systemen funktionieren. Schauen wir also auch hier einmal rein, indem wir
zuerst mit import os das Modul importieren und dann mit dir(os) uns den Inhalt des Moduls anzeigen
lassen.
Wichtige Befehle im Zusammenhang mit jedem Betriebssystem sind solche, die sich mit dem Ver-
zeichnisbaum beschäftigen. Zuerst lasse ich das aktuelle Verzeichnis anzeigen, danach wechsele ich im
Verzeichnisbaum eine Stufe hinauf:
2 >>> import os
3 >>> [Link]()
4 ’/home/martin/texte’
5 >>> [Link](’./texte’)
6 ’/home/fmartin/texte’
7 >>> [Link](’..’)
8 >>> [Link]()
9 ’/home/martin’
10
Interessant dabei ist [Link]: dieser Befehl wandelt eine relative Pfad-Angabe in einen
absoluten Pfad um.
Im vorigen Absatz sind die Ausgaben auf einem typischen Unix(Linux)-Rechner zu sehen. Unter
Windows sähe das vielleicht so aus:
2 >>> import os
3 >>> [Link]()
4 ’c:\\home\\martin\\texte’
5 >>> [Link](’..’)
6 >>> [Link]()
7 ’c:\\home\\martin’
8
Interessant an dem Modul os ist, dass man auch aus Python heraus damit Befehle des Betriebssystems
aufrufen kann. Dazu dient die Methode system. Ich lasse also hier einmal alle Dateien des aktuellen
Verzeichnisses ausgeben. Unter Linux dient dazu der Befehl ls, um eine ausführliche Darstellung zu
erhalten in der Variante ls -lsia
366
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.3. AUFRUF VON PROGRAMMEN
Im vorletzten Beispiel habe ich die unterschiedliche Darstellung des Verzeichnisbaumes unter Unix
und Windows gezeigt. Während unter Unix (und allen Abkömmlingen) das Trennzeichen zwischen
Verzeichnissen oder zwischen Verzeichnis und Datei der einfache Slash / ist, benutzt Windows den
Backslash \. Leider schert Windows nicht nur bei diesem Trennzeichen aus der Reihe, sondern auch bei
anderen Elementen des Verzeichnisbaums und der Darstellung von Dateinamen. Wenn man mit Hilfe
eines Programms also auf Datei- und Verzeichnisebene arbeiten und sein Programm portabel halten
will, muss man beide (oder vielleicht noch mehr?) Möglichkeiten berücksichtigen. Auch hier hilft das
Modul os: es kennt die Variablen
Ein interessanter Ast des Moduls os ist [Link]. Hierin sind Attribute und Methoden enthalten,
die sich mit dem Dateipfad innerhalb des Verzeichnisbaumes beschäftigen. Als Beispiel benutze ich die
Methoden basename und dirname, die einen voll-qualifizierten Dateinamen in den Verzeichnis- und
den Datei-Teil zerlegen:
2 >>> import os
3 >>> dateiVollQualifiziert = ’/home/martin/texte/PythonBuch/XML/[Link]’
4 >>> [Link](dateiVollQualifiziert)
5 ’/home/fmartin/texte/PythonBuch/XML’
6 >>> [Link](dateiVollQualifiziert)
7 ’[Link]’
8
367
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.3. AUFRUF VON PROGRAMMEN
2 martin@mas-Oberndorf:˜/public_html> ls
3 [Link]
4 [Link]
5 [Link]
6 [Link]
7 [Link]
8
Hier wurde der Unix-Befehl ls benutzt. Unter Windows lautet der entsprechende Befehl dir.
Wenn ich nur die HTML-Dateien, also die, deren Dateiendung .html lautet, angezeigt haben will,
muss ich dem Programm ls diese Information als Parameter mitgeben:
2 martin@mas-Oberndorf:˜/public_html> ls *.html
3 [Link]
4 [Link]
5 [Link]
6
Das ist natürlich auch bei einem Python-Programm möglich, das man auf der Shell (oder für Windows-
Benutzer: in der Eingabeaufforderung) startet. Kurz nachgedacht: da spielt Python doch zusammen mit
dem jeweiligen Betriebssystem! Also benötigt man wieder das Modul sys!
Das folgende Programm, von mir [Link] genannt, begrüßt alle“, wenn es
”
ohne Parameter aufgerufen wird, und eine einzelne Person, wenn der Name einer einzelnen Person als
Paramter mitgegeben wird:
if len([Link]) > 1:
print(’Hallo ’+[Link][1])
else:
print(’Hallo alle!!’)
Ob ein Parameter mitgegeben wird oder nicht, wird mit Hilfe der Länge der Parameterliste überprüft;
dabei ist wichtig zu wissen, dass jedes Programm immer einen Parameter erhält, nämlich den eige-
nen Programmnamen. Erst wenn die Länge der Liste länger als eins ist, wird ein echter“ Parameter
”
übergeben. Hier kommt als Nachweis, dass das richtig funktioniert, die Ausgabe des Programms bei
zwei Aufrufen:
368
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.4. WEITER MIT VERZEICHNISSEN: DAS . . .
Nach dem, was wir weiter oben über Fehlerbehandlung gesagt haben, geht das auch ein bißchen
eleganter:
try:
print(’Hallo ’+[Link][1])
except:
print(’Hallo alle!!’)
2 #!/usr/bin/python
3 # -*- coding: utf-8 -*-
4 import os, sys
5
6 if len([Link]) > 1:
7 for einArg in [Link][1:]:
8 try:
9 print(einArg, ’\t\t\t==>’, [Link][einArg])
10 except:
11 print(einArg+’ ist keine gültige Umgebungsvariable’)
12 else:
13 for k in [Link]:
14 print(k,’\t\t\t==>’, [Link][k])
15
369
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.5. DAS MODUL SUBPROCESS
und schöner:
import subprocess
import os
from time import sleep
import glob
bildListe = [Link](verzeichnis+’/*.jpg’)
for bild in bildListe:
x = [Link]([’xv’, bild])
sleep(5)
[Link]("kill " + str([Link]))
Zum Anzeigen der einzelnen Bilder wird hier das Programm xv benutzt. Wem das nicht gefällt, der
kann das einfach ändern. Außerdem ist fest verdrahtet, dass nur Dateien mit der Endung jpg (klein
geschrieben) angezeigt werden.
370
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.7. DAS MODUL [Link]
• [Link] archive(base name, format, root dir=None, base dir=None, ...) das
eine Archiv erzeugt
Dabei kann die Auflist-Funktion eine selbst geschriebene Funktion sein, im einfachsten Fall kann es
auch die betriebssystem-interne Funktion (unter Unix / Linux: ls) sein. Die Dateiliste ist im Normalfall
None, also die leere Liste. Das sieht so aus:
In der neuen Version ist [Link] ein Generator. Das bedeutet, dass eine Auflist-Funktion nicht mehr
als zweiter Parameter angegeben sein muss. Das sieht so aus:
[Link]
[Link]
[Link]
ue_004.pdf
ue_001.pdf
ue_005.tex
ue_003.pdf
ka_01.tex
ue_004.tex
ue_001.tex
Wenn man die vollständigen Angaben, das heißt Pfadnamen plus Dateinamen ausgeben möchte, setzt
man des vollständigen Dateinamen mit Hilfe von [Link] zusammen.
371
KAPITEL 23. PYTHON ALS SPRACHE FÜR . . . 23.7. DAS MODUL [Link]
372
Teil XII.
373
24. Texte bearbeiten für Fortgeschrittene
24.1. Natural Language Toolkit (NLTK)
NLTK wird eingebunden durch
Beachte:
Stopwörter (stopwords) sind Füllwörter, d.h. Wörter, die sehr häufig vorkommen, aber für den Inhalt
des Textes von untergeordneter Bedeutung sind, im Deutschen z.B. die Wörter ist, sind, hat, ein, der,
die, das. Diese Wörter bei der Untersuchung auszuschließen geht so:
375
KAPITEL 24. TEXTE BEARBEITEN FÜR . . . 24.1. NATURAL LANGUAGE TOOLKIT (NLTK)
Separieren des Wortstammes eines Wortes (Stemming). Für die deutsche Sprache benutze
Aufruf:
376
Teil XIII.
Mathematik (Forts.)
377
25. Mathematik (Forts.)
25.1. Das Paket numpy
numpy ist ein Paket für numerische Mathematik. Speziell beherrscht numpy Matrizen, und das soll hier
als erstes demonstriert werden. Vieles davon ist (vor allem für Mathematiker) selbsterklärend.
Die Komponenten von numpy sind in der Sprache C geschrieben. C ist eine kompilierte Sprache, und
damit sind die Komponenten von numpy sehr effektiv und von der Laufzeit her sehr schnell.
Ein kleiner Tip am Rande: auch wenn ich empfehle, immer zuerst die Hilfefunktion eines Moduls
aufzurufen, wenn man ihn zum ersten Mal benutzt: bei numpy ist das ein zweifelhaftes Vergnügen: der
Hilfetext ist 91000 Zeilen lang!
25.1.1. Matrizen
Eine große Stärke von numpy ist die Bearbeitung von Matrizen. Für den Mathematiker ist der Begriff
der Matrix bekannt. Für den Python-Programmierer ist eine Matrix eine Liste von Listen - solange, bis
er numpy kennenlernt. Und danach denkt er sich: Aha, eine Liste ist also eine (1 x n)-Matrix, eine Matrix
mit einer Zeile und n Spalten.
Weil ich gerade so schön schwitze, nehme ich mir als erstes Beispiel einmal die Temperaturen (in Grad
Celsius) in Tübingen der letzten 15 Tage vor (Juli 2019). Also rein damit in eine Liste (denn noch kenne
ich numpy nicht): tempCels = [18, 20, 21, 21, 23, 25, 26, 28, 27, 32, 27, 30, 33,
35, 37] Jetzt sollen diese Temperaturen in Grad Fahrenheit umgerechnet werden. Dazu schreibe ich
eine Funktion cels2fahr.
Und jetzt muss ich in einer Schleife jede Temperatur aus der Liste nehmen, die Funktion darauf los-
lassen und das zurückgelieferte Ergebnis in eine neue Liste schreiben.
>>> print(tempFahr)
[64.4, 68.0, 69.8, 69.8, 73.4, 77.0, 78.8, 82.4,
80.6, 89.6, 80.6, 86.0, 91.4, 95.0, 98.6]
Das, was ich im letzten Satz des vorigen Absatzes geschrieben habe, kann durch die Verwendung
von numpy vereinfacht werden; das geschieht dadurch, dass die Liste in eine eindimensionale Ma-
trix umgewandelt wird. Diese eindimensionale Matrix, eine Instanz der Klasse ndarray (das steht
für n-dimensionales Array, also n-dimensionale Matrix), wird erzeugt durch die Methode array und
überlädt die Standard-Operatoren und ermöglicht es damit auch, dass an eine Funktion ein Objekt die-
ser Klasse übergeben wird.
379
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
Es ist ein Standard in der Python-Welt, numpy wie in der ersten Zeile zu importieren.
Matrizen kann man mit numpy auf verschiedene Weisen erstellen; das umfasst auch das Erzeugen von
speziellen Matrizen.
1. Indem man ein array anlegt durch Angabe der Matrix-Werte. Hier wird eine (3 x 4)-Matrix und
eine (4 x 2)-Matrix angelegt und danach angezeigt.
Das Format einer Matrix sollte natürlich auch ausgegeben werden können.
2. matrix ist eine Unterklasse von array, mit der nur maximal zweidimensionale Felder erzeugt
werden können.
380
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
Für Objekte der Klasse matrix sind alle Rechenoperationen definiert, die man aus der Oberstufe
des Gymnasiums oder aus der Vorlesung Lineare Algebra 1“ kennt.
”
3. Mit array können auch drei- (oder höher-)dimensionale Felder angelegt werden. Ein zweidimen-
sionales Feld besitzt eine Länge und eine Breite; ein dreidimensionales Feld besitzt eine Länge, eine
Breite und eine Höhe. Gut darstellen ließe sich das durch einen Quader, aber nicht hier auf Papier
[[4 4 4]
[5 5 5]
[6 6 6]]
[[7 7 7]
[8 8 8]
[9 9 9]]]
>>> print([Link])
(3, 3, 3)
381
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
array([[0.+0.j, 2.+0.j],
[3.+0.j, 1.+0.j],
[2.+0.j, 0.+0.j],
[1.+0.j, 1.+0.j]])
>>> m2 = [Link](4,20)
>>> m2
array([ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> m3 = [Link](1,23, 3)
>>> m3
7. Eine Einheitsmatrix ist eine quadratische Matrix, in der die Elemente der Hauptdiagonalen (der
Diagonalen von links oben nach rechts unten) den Wert 1 haben, alle anderen Elemente den Wert
0. Eine Möglichkeit, sie zu erzeugen, ist die Methode identity. Sie benötigt als Parameter die
Anzahl der Zeilen.
382
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
>>> print(einhMatr5)
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]]
identity kann auch einen Datentyp als Parameter erhalten. Eine Einheitsmatrix mit ganzen Zah-
len folgt:
>>> print(einhMatr5)
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]
Eine zweite Möglichkeit, Einheitsmatrizen zu erzeugen, ist die Methode eye. Auch sie benötigt
als Parameter die Anzahl der Zeilen:
>>> print(einhMatr5)
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]
Und eye beherrscht auch, etwas ähnliches wie eine Einheitsmatrix zu bauen, die nicht quadratisch
ist. In diesem Fall benötigt eye zwei Parameter, nämlich die Anzahl der Zeilen und die Anzahl
der Spalten. Dabei muss angegeben werden, welche ”Diagonale”die Einsen enthalten soll. Die
Beschreibung ist lästig und sprachlich unschön, darum sollen 3 Beispiele genügen; in eine 3x7 -
Matrix wird die 0., die 2. und die (-2). Diagonale mit Einsen gefüllt:
383
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
>>> print(matrix_3x7)
[[1. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0.]]
>>> matrix_3x7 = [Link](3,7, k=2)
>>> print(matrix_3x7)
[[0. 0. 1. 0. 0. 0. 0.]
[0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0.]]
>>> matrix_3x7 = [Link](3,7, k=-2)
>>> print(matrix_3x7)
[[0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0.]]
8. Eine Nullmatrix ist eine Matrix, die nur Nullen enthält, eine Einsmatrix enthält nur Einsen.
>>> print(nullM)
[[0 0 0 0]
[0 0 0 0]]
>>> print(einsM)
[[1 1 1 1 1]
[1 1 1 1 1]]
9. Eine Diagonalmatrix ist eine Matrix, die in der Hauptdiagonalen von 0 verschiedene Werte hat,
alle restlichen Elemente sind 0.
384
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
>>> print(dm)
[[ 1 0 0 0]
[ 0 -2 0 0]
[ 0 0 3 0]
[ 0 0 0 -4]]
>>> print(dm[:2,:2])
[[ 1 0]
[ 0 -2]]
>>> print(dm[:2,2:])
[[0 0]
[0 0]]
>>> print(dm[1:3,1:3])
[[-2 0]
[ 0 3]]
>>> print(dm[:2,3:])
[[0]
[0]]
2. Wie schon oben bei den Listen gezeigt kann auch eine Matrix umgekehrt werden.
385
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
3. Das Format einer Matrix kann mit Hilfe der Methode arange verändert werden.
array([ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> [Link](2,8)
array([ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> [Link](4,4)
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
4. Zwei oder mehr Matrizen können zusammengefasst werden durch die Methode concatenate.
Dabei müssen die entsprechenden Formate der Einzelmatrizen passen. Das heißt genau: wenn
ich die Matrizen in der Horizontalen zusammenfassen will, müssen sie in der Anzahl der Zeilen
übereinstimmen. Sollen die Matrizen in der Vertikalen zusammengefasst werden, müssen sie in
der Anzahl der Spalten übereinstimmen.
386
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
>>> m2 = [Link](range(11,17))
>>> m2_2x3 = [Link](2,3)
>>> print(m2_2x3)
[[11 12 13]
[14 15 16]]
>>> m5 = [Link](range(21,25))
>>> m5_2x2 = [Link](2,2)
>>> print(m5_2x2)
[[21 22]
[23 24]]
In der linearen Algebra wird eine Matrix oft umgeformt, um sie einer besser handhabbaren Form zu
bearbeiten. Das bedeutet oft, sie mit dem Gauss-Verfahren auf Zeilenstufenform zu bringen. Zulässige
Operationen dazu sind
387
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
[[ 1 2 1 2]
[ 0 1 0 -1]
[ 2 3 -3 -2]]
## 1.) Multiplikation von Zeile 1 mit 5
>>> a_umf1 = [Link]([5*a1[0],a1[1],a1[2]])
>>> print(a_umf1)
[[ 5 10 5 10]
[ 0 1 0 -1]
## 2.) Addition von Zeile 2 zu Zeile 1 (Zeilen 2 und 3 bleiben unverändert)
>>> a_umf2 = [Link]([a1[0]+a1[1], a1[1], a1[2]])
>>> print(a_umf2)
[[ 1 3 1 1]
[ 0 1 0 -1]
[ 2 3 -3 -2]]
## 3.) Vertauschen von Zeile 2 und Zeile 3
>>> a_umf3 = [Link]([[a1[0], a1[2], a1[1]]])
>>> print(a_umf3)
[[[ 1 2 1 2]
[ 2 3 -3 -2]
[ 0 1 0 -1]]]
## 4.) Addition der negativen Hälfte von Zeile 3 zu Zeile 1
>>> a_umf4 = [Link]([a1[0]+(-0.5)*a1[2],a1[1],a1[2]])
>>> print(a_umf4)
[[ 0. 0.5 2.5 3. ]
[ 0. 1. 0. -1. ]
[ 2. 3. -3. -2. ]]
388
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
2. Bei der Multiplikation von Matrizen wird zuerst das Skalarprodukt betrachtet. Das Skalarprodukt
zweier Vektoren (das sind (n x 1)-Matrizen) ist eine Zahl (ein Skalar). Voraussetzung dafür ist, dass
beide Vektoren die selbe Anzahl Zeilen haben.
In Python, genauer in numpy, wird das Skalarprodukt durch die Methode dot berechnet und ist
auch auf Matrizen anwendbar. Anders als in der Analytischen Geometrie in der Schule ist hier die
Voraussetzung, dass beide Vektoren Zeilenvektoren mit der selben Anzahl Elemente sind, oder
dass der erste Vektor ein Zeilenvektor und der zweite Vektor ein Spaltenvektor ist, wobei der erste
Vektor soviele Spalten haben muss wie der zweite Vektor Zeilen hat. Umständliche Erklärung,
oder? Also schau auf das Beispiel:
389
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
>>> v2 = [Link]([[1],[2],[0]])
>>> v2
array([[1],
[2],
[0]])
>>> print([Link](v1,v2))
[-3]
### 2. Fall
>>> v1 = [Link]([1,-2,4])
>>> v1
array([ 1, -2, 4])
>>> v2 = [Link]([1,2,0])
>>> v2
array([1, 2, 0])
>>> print([Link](v1,v2))
-3
### 3. Fall
>>> v1 = [Link]([[1],[-2],[4]])
>>> v1
array([[ 1],
[-2],
[ 4]])
>>> v2 = [Link]([1,2,0])
>>> v2
array([1, 2, 0])
>>> print([Link](v1,v2))
### 4. Fall
>>> v1 = [Link]([[1],[-2],[4]])
>>> v1
array([[ 1],
[-2],
[ 4]])
>>> v2 = [Link]([[1],[2],[0]])
>>> v2
array([[1],
[2],
[0]])
>>> print([Link](v1,v2))
Wenn man die Vektoren als matrix definiert, sieht das ein wenig anders aus:
Aus der Schule kennt man nur die dritte Variante: Spaltenvektor mal Spaltenvektor ergibt Zahl.
Das funktioniert hier nicht, sondern hier muss die Bedingung für die Multiplikation von Matrizen
gelten: Anzahl der Spalten der 1. Matrix muss gleich sein der Anzahl der Zeilen der 2. Matrix. Die
geliebte Kippregel“!!
”
Das ist im obigen Beispiel die zweite Variante. Aber Vorsicht! Hier ist das Ergebnis kein Skalar
(keine Zahl), sondern eine 1x1-Matrix. Das Skalarprodukt wird richtig nur berechnet wie im 2.
Fall bei der Multiplikation mit dot von arrays.
3. Zwei Matrizen können miteinander multipliziert werden, wenn die Anzahl der Spalten der ersten
Matrix gleich ist der Anzahl der Zeilen der zweiten Matrix. Das Ergebnis der Multiplikation ist
eine Matrix des Formats ((Anzahl Zeilen der 1. Matrix) x (Anzahl der Spalten der 2. Matrix)), als
Formel (m x n) ∗ (n x p) = (m x p)
391
KAPITEL 25. MATHEMATIK (FORTS.) 25.1. DAS PAKET NUMPY
4. Die Länge eines Vektors berechnet sich als Wurzel aus dem Skalarprodukt des Vektors mit sich
selbst, also
5. Ein nettes Beispiel zur Matrizenmultiplikation: Bei einem Skatturnier wird an 5 Tischen gespielt.
Die Ergebnisse werden am Ende in einer Liste festgehalten.
Diese Ergebnisse kommen jetzt in eine (3 x 5)-Matrix. Um die Verluste bzw. Gewinne je Tisch zu
berechnen, wird die Gewinn-Verlust-Matrix gv Matr mit dieser Matrix multipliziert. Das ergibt
wieder eine (3 x 5)-Matrix, in der dann in der jeweiligen Spalten steht, was die einzelnen Spieler
eines Tisches erhalten bzw. bezahlen müssen.
392
KAPITEL 25. MATHEMATIK (FORTS.) 25.2. SYMBOLISCHE MATHEMATIK (UND . . .
Das bedeutet, dass z.B. am Tisch 1 Spieler A 169 Geldeinheiten(GE) bekommt, Spieler B 179 GE
zahlt und Spieler C 10 GE bekommt. (Die Summe in jeder Spalte muss 0 betragen!!)
[Link]. Matrizengleichungen
Auch Matrizengleichungen, also lineare Gleichungssysteme (LGS), löst numpy.
# a * x = b <=> [Link](a,b)
>>> [Link](a3,b3)
array([[ 3.],
[-1.]])
393
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Ein anderes Beispiel für symbolisches Rechnen ist das Bilden einer Ableitungsfunktion. So gilt, wie
jeder weiß,
Also schauen wir mal, was Python mit Hilfe von sympy daraus macht:
Aber auch so eine Kleinigkeit wie Kürzen von Termen oder Polynomdivision oder das lösen von
quadratischen Gleichungen beherrscht sympy:
25.3. Pandas
Pandas ist ein weiterer Python-Modul, der auf numpy basiert und dazu dient, Daten aufzubereiten, zu
analysieren und darzustellen. Pandas wird mit import pandas as pd importiert.
25.3.1. Series
Das erste Objekt aus Pandas, das ich hier vorstelle, ist die Series (Vorsicht!! Großbuchstabe!!). Eine
Series ist eine Struktur, die eine andere Struktur indiziert (also mit einem Index versieht). Eine Series
ist manchmal so ähnlich wie eine Python-Liste, und manchmal so ähnlich wie ein Python-Dictionary;
sie kann aber mehr!!
Gibt man Series ein einziges Objekt mit, so werden die Elemente des Objektes mit den natürlichen
Zahlen 0 bis (Länge des Objektes - 1) indiziert. Hier wird eine Series erstellt, die eine Liste enthält.
Diese Liste wird ausgegeben.
394
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
0 9
1 17
2 29
3 8
4 13
5 21
1
Series werden defaultmäßig mit dem natürlichen“ Index ausgegeben: es wird einfach gezählt!
”
Das kann man dadurch ändern, dass man einen Index ausdrücklich angibt: 2
Als Dictionary, ohne Verwendung von Pandas, sähe das wie im folgenden Beispiel aus. Hier kann
man auch Schlüssel und Werte separat anzeigen lassen, zudem die Einträge als Liste von Tupeln.
395
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Das geht auch mit Series, allerdings muss man ein bißchen aufpassen:
>>> [Link]()
Float64Index([0.25, 0.5, 1.0], dtype=’float64’)
>>> [Link]
array([’Viertele’, ’Halbe’, ’Maß’], dtype=object)
>>> [Link]
<bound method [Link] of 0.25 Viertele
0.50 Halbe
1.00 Maß
dtype: object>
396
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
In der pandaSerie2 werden alle Zahlen in float umgewandelt, weil 17.5 eine Fließkommazahl ist
(siehe die dtype-Angabe float). In pandaSerie3 ist der dtype object, da das die Oberklasse von String
und Float ist, ebenso in der pandaSerie4.
Im nächsten Beispiel ist das Pandas-Objekt eine von Hand erzeugte Matrix. Die Elemente, die indiziert
werden, sind folglich die Zeilen der Matrix.
397
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
>>> print(brueche)
0 1.000000
1 0.500000
2 0.333333
3 0.250000
4 0.200000
5 0.166667
6 0.142857
7 0.125000
8 0.111111
9 0.100000
dtype: float64
Das ganze kann natürlich noch schöner ausgegeben werden, indem man als zweiten Parameter von
Series durch das Schlüsselwort index eingeleitet eine Liste von Schlüsselwerten mitgibt.
>>> print(brueche)
1/1 1.000000
1/2 0.500000
1/3 0.333333
1/4 0.250000
1/5 0.200000
1/6 0.166667
1/7 0.142857
1/8 0.125000
1/9 0.111111
1/10 0.100000
dtype: float64
398
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Wird der Series als Daten ein Dictionary übergeben, werden die Schlüssel des Dictionary die Indi-
zes, die sortiert werden.
>>> print(noten)
Adam 2.0
Ina 2.8
Karl 3.5
Lena 1.4
Lisa 2.1
Sepp 3.2
dtype: float64
Aber Vorsicht: man muss hierbei darauf achten, bei Dictionaries habe ich das schon einmal geschrie-
ben, dass die Schlüssel eindeutig sind. Wird ein Schlüssel doppelt verwendet, wird der erst zu diesem
Schlüssel gehörende Wert durch den zweiten Wert überschrieben:
399
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Mit apply kann man eine Funktion auf die Series loslassen. Hier wird das gezeigt mit einer Serie
von Temperaturen.
>>> print(tempSeries)
Berlin 22
Colmar 20
Paris 21
Rottenburg 21
Wessling 18
dtype: int64
>>> [Link](celsius2fahrenheit)
Berlin 71.6
Colmar 68.0
Paris 69.8
Rottenburg 69.8
Wessling 64.4
dtype: float64
Weil es so schön ist, folgt hier die Berechnung des Bruttopreises (also inklusive Mehrwertsteuer) einer
Liste von Waren.
400
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
>>> [Link](mwstBerechnen)
D530 11.1720
D532 12.4526
D555 12.7718
D830 12.1334
dtype: float64
>>> [Link](bruttoPreisBerechnen)
D530 69.9720
D532 77.9926
D555 79.9918
D830 75.9934
dtype: float64
Aber Vorsicht! Das ist noch keine Veränderung der Werte in der Series!!
Das nächste Beispiel: ein Metallwarenhändler verkauft Schrauben in den Größen M2 bis M6. Wenn
der Bestand in einer Größe unter 150 sinkt, sollen 100 Stück nachbestellt werden.
401
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
>>> [Link](nachbestellen)
M2 412
M3 183
M4 312
M5 532
M6 230
dtype: int64
Das selbe Problem soll jetzt objektorientiert angegangen werden. Hier kommt zuerst die Klassendatei
mit dem Manko, dass die Waren des Unternehmens vorläufig fest in der Klassendatei festgeschrieben
sind. Das muss also noch geändert werden.
402
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
import pandas as pd
class Warenlager():
def __init__(self):
[Link] = [Link]([412, 83, 312, 532, 130],
index = [’M’+str(i) for i in range(2,7)])
def verkaufen(self):
[Link] = input(’Bezeichnung der Ware: ’)
[Link] = int(input(’Menge: ’))
[Link][[Link]] -= [Link]
def bestandAnzeigen(self):
print(’===========\n’, [Link], ’===========\n’)
meineWaren = Warenlager()
print(’vor Aktionen’)
[Link]()
for i in range(2):
[Link]()
print(’nach Verkauf’)
[Link]()
[Link] = [Link]([Link])
print(’ nach Nachbestellung’)
[Link]()
403
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Und es funktioniert:
nach Nachbestellung
===========
M2 412
M3 183
M4 212
M5 532
M6 230
dtype: int64 ===========
nach Nachbestellung
===========
M2 412
M3 183
M4 212
M5 182
M6 230
dtype: int64 ===========
404
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Hier wurde eine csv-Datei vom Statistischen Bundesamt heruntergeladen, der monatlicher Verbrau-
cherpreisindex. Die Datei enthält die monatlichen Daten der Jahre 2017 bis 2019. Hier wurde einge-
schränkt auf den Januar der angegebenen Jahre; diese Daten stehen in den Spalten 2, 14 und 26. Außer-
dem wurden die ersten 7 Zeilen ignoriert, in denen nur eine Beschreibung der Datei mit zusätzlichen
Informationen steht. Aus der gelesenen csv-Datei wurde dann ein DataFrame gemacht und dieser aus-
gegeben. Bei der Ausgabe sind nur die ersten 18 Datenzeilen hierhin kopiert.
Dann habe ich hier noch das Literaturverzeichnis dieses Skriptes mit Pandas bearbeitet. Sämtliche
Dateien dieses Skriptes sind docbook-xml-Dateien. Ein Eintrag im Literaturverzeichnis sieht so aus:
405
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Diese Datei wird jetzt mit folgendem Programm gelesen und bearbeitet:
import [Link] as et
import pandas as pd
def knotenWertHolen(knoten):
if knoten is not None:
return [Link]
else:
return None
# if knoten is not None else None
geparsteDatei = [Link]("/home/fmartin/texte/Python3Buch/XML/[Link]")
ausgabeSpalten = [’Name’, ’Vorname’, ’Titel’]
biblioDataFrame = [Link](columns=ausgabeSpalten)
biblioDataFrame = [Link](
[Link]([knotenWertHolen(nn), knotenWertHolen(vn),
str(knotenWertHolen(titel)).strip()], index=ausgabeSpalten),
ignore_index=True)
print(biblioDataFrame)
406
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Mehrdimensionale Datenfelder (oft Matrizen) beherrscht bereits das Standard-Python. Weiter oben wur-
de dann das ndarray von numpy angesprochen. Die DataFrames von pandas sind auch mehrdimen-
sionale Felder, bei denen noch zusätzlich Zeilen- und Spaltenbezeichnungen angegeben werden können.
Außerdem sind die DataFrames in der Lage, mit fehlenden Einträgen in den Feldern umzugehen.
[Link]. Series
Wenn die Series als Dictionary angelegt wurde, kann man auf einzelne Elemente und auf eine Teil-
menge der Elemente auf 2 Arten zugreifen:
Zu beachten dabei ist, dass beim Zugriff über den Index die altbekannte Regel von Listen gilt: Anfangs-
element inklusive, Endelement exklusive. Beim Slicen über die (explizit angegebenen) Schlüssel werden
sowohl Anfangs- als auch Endelement ausgegeben.
407
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
>>> noten[’Karl’]
3.5
>>> noten[’Ina’:’Lisa’]
Ina 5.0
Karl 3.5
Lena 1.4
Lisa 2.1
dtype: float64
>> noten[2]
3.5
>>> noten[1:3]
Ina 5.0
Karl 3.5
dtype: float64
408
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Der Wirrwarr mit den verschiedenen Arten der Indizierung wird im folgenden Beispiel hoffentlich
klar:
1. loc
2. iloc
3. ix
loc benutzt immer den explizit angegebene Index ... wenn er existiert. Das kann also auch noch zu
Verwirrung führen.
3 Ich
weiß nicht, ob das pythonisch ist. In Python liegt ja vieles in der Verantwortung des Programmierers, von dem man an-
nimmt, dass er weiß, was er tut.
409
KAPITEL 25. MATHEMATIK (FORTS.) 25.3. PANDAS
Im datenWirrwarr3, in dem keine expliziter Schlüssel angegeben ist, wird der natürliche Schlüssel
genommen, und das erwartet man nicht.
iloc hingegen benutzt immer den natürlichen Schlüssel, auch wenn explizit ein Schlüssel angegeben
wird.
410
Teil XIV.
Glossar
411
Glossar
A
Algorithmus Ein Algorithmus ist eine Vorschrift, die aus einzelnen Anweisungen besteht. Diese Vor-
schrift dient dazu, ein gegebenes Problem zu lösen. Das Wort Algorithmus ist eine Verballhor-
nung des Namens Muhammed al-Chwarizmi, eines arabischen Gelehrten aus dem 9. Jahrhundert
n. Chr.
In der Programmierung dient ein Algorithmus dazu, ein Programm zu schreiben, das ein Pro-
blem löst. Dabei werden die Anweisungen des Algorithmus in Befehle einer Programmiersprache
übersetzt.
C C ist eine Programmiersprache, die sehr eng mit dem Betriebssystem Unix verbunden ist. Beim Ent-
wurf von Unix war ein Ziel, den Code des Betriebssystems rechnerunabhängig und besser wart-
bar zu schreiben. Das war in Maschinensprache oder Assembler, wie es bis dahin üblich war, nicht
gut möglich. Die Entwickler von Unix entwarfen zu diesem Zweck eine Programmiersprache, die
auf alle möglichen Probleme anwendbar war, strukturierte Programmierung ermöglichte, aber
trotzdem systemnah arbeitet. Ein wesentliches Sprachelement von C ist der Pointer (auf deutsch:
Zeiger), ein Verweis auf einen Speicherplatz. C-Programme zeichnen sich dadurch aus, dass sie
schnell sind, weil sie (unter anderem) Speicherplätze nicht über deren Namen, sondern über die
Adresse ansprechen.
CGI Common Gateway Interface. Eine standardisierte Schnittstelle zwischen einem Programm (meis-
tens in einer P-Sprache, also PHP, perl, oder Python) und einem Web-Server.
COBOL COBOL steht für Common Business Oriented Language. Diese Sprache ist geeignet für die Pro-
grammierung von wirtschaftlichen Anwendungen. Was sich die Entwickler dieser Sprache dabei
gedacht haben? Ob sie Wirtschaftswissenschaftler und Kaufleute für unfähig, eine formale Spra-
che zu lernen, gehalten haben? Stellen wir einfach einmal gegenüber, wie ein kleineres Problem in
Python und in COBOL gelöst wird. Zuerst in Python:
a = 3
b = 5
c = a + b
und jeder wird verstehen, dass c danach den Wert 8 hat. Jetzt das selbe in COBOL:
MOVE 3 TO a.
MOVE 5 TO b.
ADD b TO a GIVING c.
Okay, das kann man auch lesen. Vor allem wegen der schönen Punkte am Ende jedes Statements.
Aber wer will so etwas schreiben???
Compiler Ein Compiler ist ein Programm, das einen Quelltext in eine vom jeweiligen Computer ausführbare
Datei umwandelt. Dabei wird der gesamte Quelltext genommen, auf Syntax-Fehler, semantische
Fehler und auch auf Schreibfehler untersucht, in der Regel mit den benötigten Bibliotheken ver-
knüpft und in Maschinensprache übersetzt. 4
CSS Cascading Style Sheets sind Dateien, die Formatierungsanweisungen für verschiedene Auszeich-
nungssprachen (HTML, XML) enthalten
4 siehe auch [Compiler]
413
GLOSSAR GLOSSAR
DBMS Database Management System. Ein DBMS ist eine Kombination von Datenbanken mit ihren
Tabellen, ihren Zugriffsrechten, ihren Zugriffsbefehlen und manchmal noch mit eine grafischen
Oberfläche.
Default ist das, was standardmäßig vorgegeben ist, sprachlich taucht es meistens als Defaultwert auf.
DTD Document Type Definition. Hier wird ein Modell eines XML-Dokuments beschrieben.
Dummy Ein Dummy ist ein Stellvertreter für irgendetwas. Er zeichnet sich dadurch aus, dass er sich gar
nicht auszeichnet: ein Dummy hat nichts und kann nichts von dem, was das Original auszeichnet.
Fortran Fortran ist die Zusammenschreibung der ersten Silben von Formular translator“. Daraus geht
”
schon hervor, dass diese Programmiersprache sich in Mathematik, Physik und den Ingenieurwis-
senschaften zu Hause fühlt. Fortran-Compiler sind meistens recht teuer, aber die Sprache ist nicht
vergnügungssteuerpflichtig. Nein, es macht nicht unbedingt Spaß, Fortran zu programmieren,
aber die Sprache kann mit Zahlen dafür sehr gut umgehen.
HTML Hypertext Markup Language. Die Sprache des Internet. HTML ist eine Seitenbeschreibungsspra-
che, die sich als Standard für Internet-Seiten durchgesetzt hat.
Interpreter Ein Interpreter wandelt (im Gegensatz zum Compiler) einen Quelltext nicht als Ganzes in
Maschinensprache um, sondern zeilenweise. Das bedeutet, dass der Quelltext erst zur Laufzeit des
Programms auf Korrektheit untersucht wird. Ist der Maßstab für ein Programm die Ausführungsgeschwindigkeit,
so sind interpretierte Programme langsamer als compilierte, weil vor der Ausführung eines Be-
fehls dieser erst in Maschinensprache übersetzt werden muss. 5
Monty Python Englische Komikertruppe. Hier sind einige Internet-Seiten zu Monty Python:
• <[Link]
• <[Link]
• Welcome to the completely unauthorized, completely silly, and completely useless Monty
Python web site! <[Link]
414
GLOSSAR GLOSSAR
perl perl ist eine der drei P-Sprachen, die bei der Erstellung dynamischer Internet-Seiten benutzt wird.
perl wird interpretiert und hat seine Stärken in der Behandlung von Texten.
perl ist die eierlegende Wollmilchsau. In perl kann man alles machen, vor allem kann man alles
kaputt machen. Böse Menschen behaupten, das Motto von perl sei write once, never read again“,
”
und das ist durchaus ernst zu nehmen: oft versteht der perl-Programmierer schon nach einer Wo-
che nicht mehr, was er da geschrieben hat.
Pseudocode Pseudocode ist kein Programmcode in irgendeiner Programmiersprache, sondern die
Formulierung eines Algorithmus in Umgangssprache, wobei aber die logische Struktur program-
miersprachenähnlich abgebildet wird. So werden in Pseudocode etwa die typischen reservierten
Wörter für Alternativen und Iterationen (if - then - elseif - else bzw. while . . . bzw. for . . . ) benutzt,
die Aktionen, die auf diese Strukturierungsmittel folgen, in Umgangssprache beschrieben.
Quelltext, auch Quellcode Der Quelltext eines Programms ist das, was der Programmierer schreibt.
Dazu benutzt er eine Programmiersprache. Den Quelltext versteht der Computer noch nicht; er
muss erst in Maschinensprache umgewandelt werden.
UML UML ist die Abkürzung für Unified Modelling Language, die Softwaresysteme, Geschäftsprozesse,
aber auch Unternehmensmodelle veranschaulichen soll. Gleichzeitig ist UML auch Basis für die
Konstruktion von Software auf der Basis dieser Modelle und für deren Dokumentation. UML hat
viele Unter-“Sprachen, die verschiedene Diagrammarten hervorbringen. Diese ergeben sich aus
”
den verschiedenen Perspektiven, unter denen man Geschäftsprozesse, die beteiligten Objekte und
die Akteure betrachtet. Die wichtigsten Diagrammarten von UML sind:
• Klassendiagramme
• Anwendungsfalldiagramme
• Zustandsdiagramme
• Aktivitätsdiagramme
Die Sprache hat begonnen, sich durchzusetzen, als Software immer komplexer wurde und die
Wiederverwertbarkeit von Software für Unternehmen ein wichtiges Kriterium wurde.
Für die Programmierung — also für den vorliegenden Text — sind nur Klassendiagramme von
Bedeutung.
URL URL ist die Abkürzung für Uniform Resource Locator. Es handelt sich hier um eine Adress-
Angabe im WWW, zusammen mit einer Angabe, mit welchem Protokoll die Daten übermittelt
werden, z.B. http oder ftp.
415
GLOSSAR GLOSSAR
XML XML ist die Abkürzung für Extensible Markup Language. In einer Markup Language werden
— anders als in einem Textverarbeitungsprogramm — keine Eigenschaften des Aussehens wie
Schriftgröße oder Schriftstil festgelegt, sondern Textstellen wird eine Klasse zugeordnet, etwa die
Klasse Kapitelüberschrift“. Erst in einem weiteren Schritt wird dann allen mit Kapitelüberschrift
”
ausgezeichneten Elementen ein Aussehen verpasst. Es handelt sich dabei um eine logische Aus-
zeichnung, die aber auch eine semantische Bedeutung zum Inhalt hat. So erwartet XML etwa,
dass nach einer Kapitelüberschrift ein Absatz kommen muss, sicher aber keine Buchüberschrift
kommen darf. XML erwartet also sauber strukturierte Dokumente.
416
A. Arbeitsblätter zu Klassen (Danke, Jens!)
417
ANHANG A. ARBEITSBLÄTTER ZU . . .
A.0.2. Vererbung
418
ANHANG A. ARBEITSBLÄTTER ZU . . .
419
ANHANG A. ARBEITSBLÄTTER ZU . . .
A.0.4. Polymorphie
420
ANHANG A. ARBEITSBLÄTTER ZU . . .
A.0.5. Übungsaufgabe
421
ANHANG A. ARBEITSBLÄTTER ZU . . .
422
ANHANG A. ARBEITSBLÄTTER ZU . . .
A.0.7. Klassenarbeit
423
ANHANG A. ARBEITSBLÄTTER ZU . . .
424
ANHANG A. ARBEITSBLÄTTER ZU . . .
425
427
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12-1
Python
Objektorientierte Systementwicklung
Arbeitsauftrag 1
Python Shell testen
1. Starten Sie die Python Shell über Start - Programme – Python
a) Geben Sie nach dem Prompt folgende Anweisung ein:
„Wie viel ist eins und eins?“
Wie lautet das Ergebnis des Python-Interpreters?
SyntaxFehler, da der Python Interpreter kein Deutsch versteht,
sondern nur Python kann
b) Geben Sie nach dem Prompt folgende Anweisung ein:
2*3+6
Warum versteht der Python Interpreter diese Anweisung?
Die Sprache der Mathematik ist international und sie ist Teil der
Python Sprache
428
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12-1
Python
Objektorientierte Systementwicklung
Arbeitsauftrag 2
Python als Taschenrechner
1. Rufen Sie die Entwicklungsumgebung IDLE auf. Ermitteln Sie die Ergebnisse der
folgenden 4 Aufgaben:
429
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 3
Python als Taschenrechner (Variablen und Zuweisung)
1. Aufgabe: Die Umsatzsteuer in Deutschland beträgt 19%. Berechnen Sie
mithilfe von Python für die folgenden (Netto-)Rechnungsbeträge die
Umsatzsteuer. Vereinfachen Sie Ihre Berechnungen, indem Sie den
Umrechnungsfaktor zunächst in einer Variablen mit sinnvoller Bezeichnung
speichern.
a) 100€
b) 12.500,00€
2. Zusatzaufgabe: Sie haben bei Sportscheck Laufschuhe eingekauft und
bekommen eine Rechnung über 178,50€ (Bruttobetrag inklusive 19%
Umsatzsteuer) zugesandt. Berechnen Sie die Höhe des Nettobetrags Ihrer
Rechnung mithilfe einer Formel in Python. Verwenden Sie hierzu Ihre Variable
für die Umsatzsteuer aus Aufgabe 1.
430
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 4
Erstes Python Programm mit PyScripter als IDLE
1. Schreiben Sie mithilfe des PyScripter ein Python Programm mit der Ausgabe
„Mein erstes Python Programm!“. Speichern Sie das Programm unter dem
Namen AB_4.py in Ihrem Verzeichnis.
431
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 5
Variablen, Operatoren und Zeichenketten
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite
dieses Arbeitsblatts.
432
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 6
Einfache Verzweigungen mit IF….ELSE…
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
a) Ein Programm (eine Applikation) soll erstellt werden, die einen Warnhinweis
(„Bitte nachbestellen“) ausgibt, wenn der Lagerbestand einen vorab gesetzten
433
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 7
Mehrfache Verzweigungen mit IF….ELSE…
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
a) Die Bit and Byte GmbH erhebt für Bestellungen unter 100,- Euro einen Porto-
und Verpackungsanteil von 5,50 Euro, von 100,- bis 200,- Euro einen Betrag von
434
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 8
Schleifen als Kontrollstrukturen (for-Schleife)
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
a) Schreiben Sie ein Programm zur Berechnung der Quadratzahlen für die Zahlen
von 1-10. Verwenden Sie die for-Schleife.
435
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 8b
Verschachtelte for-Schleife
1. Lösen Sie die folgenden Aufgaben mithilfe Ihrer Kenntnisse zu Schleifen
a) Schreiben Sie ein Programm mittels einer Schleife, welches folgende Ausgabe
erzeugt.
b) Schreiben Sie ein Programm mittels zweier Schleifen, welches obige Ausgabe
erzeugt. Speichern Sie das Programm unter AB8b_AufgabeB.py.
c) Schreiben Sie ein Programm mittels einer Schleife, welches folgende Ausgabe
erzeugt.
Zusatzaufgabe: Überlegen Sie selbst eine kaufmännische Problemstellung, bei der Sie
die for-Schleife sinnvoll in Ihre Programmstruktur einbinden können. Speichern Sie
das Programm unter AB8_Zusatzaufgabe.py.
436
ANHANG B. ARBEITSBLÄTTER ZU . . .
Aufgabe 1b
Schreiben Sie ein Programm mittels zweier Schleifen, welches folgende
Bildschirmausgabe erzeugt:
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
Aufgabe 1c
Schreiben Sie ein Programm mittels Schleifen, welches folgende
Bildschirmausgabe erzeugt:
x
xx
xxx
xxxx
xxxxx
xxxxxx
xxxxxxx
xxxxxxxx
xxxxxxxxx
xxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxxx
Aufgabe 1d
Schreiben Sie ein Programm mittels Schleifen, welches folgende
Bildschirmausgabe erzeugt:
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxxxx
Aufgabe 1e
Schreiben Sie ein Programm mittels Schleifen, welches folgende
Bildschirmausgabe erzeugt:
xxxxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxx
xxxxxxx
xxxxx
xxx
x
437
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 9
Schleifen als Kontrollstrukturen (while-Schleife)
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
a) Schreiben Sie ein Programm zur Berechnung des jährlichen Kontostands. Das
Startguthaben soll 1500€ betragen. Der Zinssatz liegt bei jährlich 5,5%. Das
438
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 10
Funktionen
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
a) Schreiben Sie ein Programm das folgende Ausgabe im Interpreter über eine
Funktion gruss() erzeugt.
439
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 11a
Zeichenketten und Operatoren
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
440
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 11b
Zeichenketten und Funktionen
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite dieses
Arbeitsblattes.
441
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 12a
Einführung in die objektorientierte Systementwicklung
1. Lösen Sie mithilfe nachfolgender Angaben die Aufgaben von AB12b.
442
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 13
Unified Modelling Language
1. Lösen Sie mithilfe der folgenden Angaben die Aufgaben auf der Rückseite
dieses Arbeitsblattes.
443
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 14
Erzeugung von Klassen und Objekten
Aufgabe:
a) Schreiben Sie in Python eine Klasse mit Konstruktor zu Ihrem UML-
Diagramm von Arbeitsblatt 13 - Aufgabe 1b).
b) Erzeugen Sie 2 verschiedene Instanzen (Objekte) der Klasse Auto.
444
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 15
Erweiterung von Klassen
Aufgabe:
a) Erweitern Sie die Klasse Auto von AB14 um eine Methode fahren. Die
Methode fahren soll z.B. ausgeben: Auto x faehrt y km/h!
b) Instanziieren Sie ein Objekt, das anschließend durch Aufruf der Methode
fahren folgende Ausgabe erzeugt: VW Golf faehrt 40 km/h
c) Finden Sie weitere Methoden zur Klasse Auto und nutzen Sie diese Methoden
bei der Instanziierung von Objekten.
445
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 15 (Zusatzaufgabe)
Erweiterung von Klassen
Aufgabe:
a) Modellieren Sie mithilfe von UML eine Klasse Fahrzeug unter folgenden
Bedingungen. Ein Fahrzeug hat unter anderem die Eigenschaften
Bezeichnung und Geschwindigkeit. Außerdem kann man ein Fahrzeug
beschleunigen. Dadurch erhöht sich die Geschwindigkeit. Die aktuelle
Geschwindigkeit soll jederzeit angezeigt werden können.
b) Programmieren Sie die Klasse Fahrzeug aus Aufgabe a) in Python. Speichern
Sie die Klasse unter dem Dateinamen AB15_cl_Fahrzeug.py in Ihrem
Schuelerverzeichnis ab.
c) Erzeugen Sie innerhalb dieser Datei eine Instanz (ein Objekt) der Klasse
Fahrzeug mit der Bezeichnung audi. Die Ausgangsgeschwindigkeit des Audi
beträgt 0 km/h. Beschleunigen Sie das Objekt audi auf 120km/h. Geben Sie
die aktuelle Geschwindigkeit aus. Speichern Sie das Objekt unter dem
Dateinamen AB15_o1_Fahrzeug.py in Ihrem Schuelerverzeichnis ab.
Zusatzaufgabe:
Ergänzen Sie die Klasse Fahrzeug um weitere Eigenschaften und Methoden Ihrer
Wahl.
446
ANHANG B. ARBEITSBLÄTTER ZU . . .
Datum
Informatik WG12
Python
Objektorientierte Systementwicklung
Arbeitsblatt 16
Import von Klassen
Aufgabe:
a) Modellieren Sie mithilfe von UML eine Klasse Konto unter folgenden
Bedingungen. Ein Konto verfügt über eine Kontonummer, eine Bankleitzahl,
einen Zinssatz, einen Kontostand und einen Kontoinhaber. Es kann Geld auf
das Konto eingezahlt werden bzw. Geld vom Konto abgehoben werden.
Außerdem soll der aktuelle Kontostand angezeigt werden können.
b) Programmieren Sie die Klasse Konto aus Aufgabe a) in Python. Beachten Sie
dass bei der Einzahlung der Kontostand erhöht wird und bei der Abhebung
der Kontostand verringert wird. Speichern Sie die Klasse unter dem
Dateinamen AB16_cl_Konto.py in Ihrem Schuelerverzeichnis ab.
c) Importieren Sie die Klasse in eine neue Datei. Erzeugen Sie innerhalb dieser
Datei eine Instanz (ein Objekt) der Klasse Konto mit der Bezeichnung
meinKonto. Die Wertausprägung der Attribute ist frei wählbar. Sie können
beispielsweise die Angaben Ihres eigenen Kontos nehmen. Speichern Sie das
Objekt unter dem Dateinamen AB16_o1_Konto.py in Ihrem
Schuelerverzeichnis ab.
d) Programmieren Sie verschiedene Einzahlungen und Auszahlungen Ihres
Kontos mit anschließender Anzeige des aktuellen Kontostands.
447
C. Lösungen zu Aufgaben
C.1. aus Kapitel 7: Programmstrukturen
Wochentagsberechnung.
#!/usr/bin/python
#-*- coding: utf-8 -*-
# berechnet zu einem Datum den Wochentag
b = (13 * monat_r - 1) / 5 + a / 4 + c / 4
wotag = (b + a + tag - 2 * c) % 7
#!/usr/bin/python
for i in range(1,40,2):
z = ’*’*i
print([Link](40,’ ’))
Quadratzahlen.
#!/usr/bin/python
# -*- coding: utf-8 -*-
449
ANHANG C. LÖSUNGEN ZU AUFGABEN C.2. AUS KAPITEL 8: SCHLEIFEN
for i in range(endZahl+1):
print("%i*%i = %i" % (i, i, i*i))
#!/usr/bin/python
alleZahlen = range(1,schranke+1)
alleZahlen[0] = ’x’
start = alleZahlen[1]
while start*start < schranke:
n = 2
while start*n <= schranke:
alleZahlen[start*n - 1] = ’x’
n += 1
k = 0
while type(alleZahlen[start+k]) != int:
k +=1
start = alleZahlen[start+k]
print("\n\nSo! Das sind jetzt alle Primzahlen bis ",schranke,"!!")
primz = []
for x in alleZahlen:
if type(x) == int:
[Link](x)
print(primz)
Größter gemeinsamer Teiler und kleinstes gemeinsames Vielfaches mit dem Euklidschen Algo-
rithmus.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# berechnet ggT und kgV zweier Zahlen mit dem Euklidschen Algorithmus
450
ANHANG C. LÖSUNGEN ZU AUFGABEN C.2. AUS KAPITEL 8: SCHLEIFEN
Stellenwertsysteme.
#!/usr/bin/python
restliste = []
while(zahl > 0):
(zahl,rest) = divmod(zahl, modus)
if modus > 10:
restAlpha = mehrAlsHex[rest]
[Link](restAlpha)
else:
[Link](rest)
[Link]()
for i in restliste:
print(i,end=’,’)
#!/usr/bin/python
z1 = [15, 38, 46]
z2 = [12, 47, 58]
sum = [0,0,0]
uebertrag = 0
for i in range(len(z1)-1,-1,-1):
if i > 0:
sum[i] = (z1[i] + z2[i] + uebertrag) % 60
uebertrag = (z1[i] + z2[i]) / 60
else:
sum[i] = (z1[i] + z2[i] + uebertrag) % 60
print(sum)
Drucker - Abrechnung.
#!/usr/bin/python
# -*- coding: utf-8 -*-
print(’Druckkosten-Berechnung’)
print(’Menge\tGesamtkosten\tKosten je Blatt’)
fixkosten = 840.34
stueckkosten = 0.038
mindestAbnahme = 2000
mwstSatz = 0.19
451
ANHANG C. LÖSUNGEN ZU AUFGABEN C.2. AUS KAPITEL 8: SCHLEIFEN
Sierpinski - Pfeilspitze. Zuerst ein Modul, das die Fakultäten und den Binomialkoeffizienten berech-
net:
#!/usr/bin/python
# -*- coding: utf-8 -*-
def fak(zahl):
fakultaet = 1
for i in range(zahl, 0, -1):
fakultaet *= i
return fakultaet
if __name__ == ’__main__’:
z = int(input(’Fakultät bis ... ’))
print(fak(z))
Und hier das Programm für die Pfeilspitze (es ist wieder peinlich kurz!):
#!/usr/bin/python
from fakultaet import binko
for i in range(0,30,1):
z = ’’
for j in range(i+1):
if binko(i, j)%2 == 0:
z += ’ ’
else:
z += ’x’
print(z)
Staaten mit Hauptstädten (selbstlernend). Hier zuerst das Programm, das die ganze Intelligenz zum
Inhalt hat:
#!/usr/bin/python
""" Dokumentation von [Link]
Ein Dictionary Land -> Hauptstadt wird eingerichtet.
452
ANHANG C. LÖSUNGEN ZU AUFGABEN C.2. AUS KAPITEL 8: SCHLEIFEN
def initialisiere():
global LaHa
global neuLaHa
neuLaHa= {}
LaHa = {’Italien’:’Rom’,
’Frankreich’:’Paris’,
’Deutschland’:’Berlin’,
’Belgien’:’Bruessel’,
’Spanien’:’Madrid’}
def hilfe():
for land in LaHa:
print(land, ’\t’, LaHa[land])
def raetsel():
punkte = 0
fehler = 0
for land in LaHa:
frageHText = ’Wie heisst die Hauptstadt von ’+land+’?’
stadt = input(frageHText)
if LaHa[land] == stadt:
punkte += 1
print("Gut!!")
else:
print(’so nicht’)
print(’schau im Lexikon nach!’)
tippfText = ’(falls Deine Eingabe "’+stadt
+ ’" nur ein Tippfehler war, gib jetzt das Wort "Tippfehl
neuesLand = input(frageLText)
if neuesLand == ’Tippfehler’:
pass
else:
neuLaHa[neuesLand] = stadt
fehler += 1
#!/usr/bin/python
import LandHauptst
print(LandHauptst.__doc__)
453
ANHANG C. LÖSUNGEN ZU AUFGABEN C.2. AUS KAPITEL 8: SCHLEIFEN
LaHa = {}
neuLaHa = {}
[Link]()
while [Link]() > 0:
1
Caesar-Verschlüsselung.
#!/usr/bin/python
# -*- coding: utf-8 -*-
#!/usr/bin/python
# -*- coding: utf-8 -*-
454
ANHANG C. LÖSUNGEN ZU AUFGABEN C.3. AUS KAPITEL 10: FUNKTIONEN
#!/usr/bin/python
# -*- coding: utf-8 -*-
zz = 0
for zeile in [Link]():
ausZeile = ’’
for zeichen in zeile:
ausZeile += chr((ord(zeichen) + ord(schlWort[zz % len(schlWort)]))% 255)
zz += 1
[Link](ausZeile)
[Link]()
[Link]()
#!/usr/bin/python
def ableitung(x):
abl = 3 * x**2
return abl
fwert = 100
startwert = 1.0
schwelle = 0.0000001
x = startwert
Römische Zahlen.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
455
ANHANG C. LÖSUNGEN ZU AUFGABEN C.3. AUS KAPITEL 10: FUNKTIONEN
einsFuenfZehn(2, decHun)
einsFuenfZehn(1, decZeh)
einsFuenfZehn(0, decEin)
print(roZa)
456
D. Literatur zu Python
Literatur
[ABOP] A Byte of Python, C.H. Swaroop, Copyright c 2003-2005 Creative Commons Attribution-
NonCommercial-ShareAlike License 2.0, .
[Compiler] <[Link] , , Copyright c , . 4
[DocBook-XML] DocBook-XML, Thomas Schraitle, Copyright c 2004 SuSE Press, 3-89990-078-2. (docu-
ment)
[Evans] Introduction to Computing , David Evans, Copyright c
[Link] . 17, 19
[FSF] <[Link] , Copyright c , . 10
[Freie Software] Freie Software, Volker Grassmuck, Copyright c 2002 Bundeszentrale für politische Bil-
dung Bonn, 3-89331-432-6. 9
[Friedl] Mastering Regular Expressions , Jeffrey E.F. Friedl, Copyright c 2002 O’Reilly, 0-596-
00289-0. 5.5
[Interpreter] <[Link] , , Copyright c , . 5
[Java] Thinking in Java, Bruce Eckel, Copyright c 2003 Prentice Hall, 3-8272-6896-6. (docu-
ment)
[Lubanovic] Introducing Python , Bill Lubanovic, Copyright c 2015 O’Reilly, 978-1-449-35936-2.
[Lusth] The Alchemy of Programming: Python <[Link]
[Link]> , John C. Lusth, Copyright c 2012 , . 3.3.5
[Lutz/Ascher] Einführung in Python, Mark LutzDavid Ascher, Copyright c 2007 O’Reilly, Köln, 3-
89721-488-0.
[Programming Python] Programming Python, Mark Lutz, Copyright c 2006 O’Reilly, Sebastopol, CA
95472, USA, 0-596-00925-9. 3, 5, 5, 2.6.1, 4, 20.6
[Programming Python2] Programming Python, Mark Lutz, Copyright c 1996 O’Reilly, Sebastopol, CA
95472, USA, 1-56592-1975-6. 13
[Python] Python, Peter Walerowski, Copyright c 2009 Addison-Wesley, 978-3-8273-2517-4. 6
[Python and XML] Python and XML, Christopher A. JonesFred L. Jr. Drake, Copyright c 2002 O’Reilly,
Köln, 3-89721-175-0. (document)
[SWFK] Schlangengerangel für Kinder , Jason Briggs, Copyright c
[Link] .
[Severance] Python for Informatics , Charles Severance, Copyright c
[Link] .
[VdP] Python Data Science Handbook , Jake VanderPlas, Copyright c 2017 O’Reilly, 978-1-491-
91205-8.
[dummdeutsch] Dummdeutsch, Eckard Henscheid, Copyright c 1993 Reclam, Stuttgart, 3-15-008865-8.
14
457
E. Index
459
ANHANG E. INDEX
460
ANHANG E. INDEX
461
ANHANG E. INDEX
462
ANHANG E. INDEX
463