Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain
Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain
Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>Programmieren</strong> 3<br />
<strong>Programmieren</strong> in C und Python<br />
Prof. Dr. Peter Barth<br />
<strong>Hochschule</strong> <strong>RheinMain</strong><br />
Fachbereich Design Informatik Medien<br />
<strong>Medieninformatik</strong><br />
29. Januar 2013<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 1 / 326
Organisatorisches<br />
Organisatorisches<br />
Vorlesung<br />
• Dienstags, 10:00 – 11:30 Uhr, Raum 11<br />
Praktikum<br />
• Duchmann: Di R13: C ab 8:15 Uhr, B ab 11:45 Uhr<br />
• Barth: Mo R13: E ab 16:00 Uhr, Di R15: A ab 11:45 Uhr,<br />
Mi R15: D ab 16:00 Uhr<br />
Vorlesungsfolien, Übungsblätter, weitere Informationen<br />
• Read.MI<br />
• http://www.mi.hs-rm.de/˜barth/hsrm/prog3<br />
Bewertung<br />
• Prüfungsleistung, Klausur 70 %<br />
• Studienleistung, Praktikum 30 %<br />
• Online-Test C<br />
• Online-Test Python<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 2 / 326
Organisatorisches<br />
Bewertung Praktikum<br />
Erreichbar<br />
• Online-Test C<br />
• Online-Test Python<br />
• Bonus beide Tests > 3 Punkte<br />
Bestanden<br />
• Mindestens 6 Punkte<br />
• Bis 9 Punkte ausreichend<br />
Keine Wiederholung der Online-Tests<br />
21 Punkte<br />
9 Punkte<br />
9 Punkte<br />
3 Punkte<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 3 / 326
Organisatorisches<br />
Ziele der Veranstaltung<br />
Weitere Sprachparadigmen und Sprachebenen verwenden<br />
• Umgang mit anderen Arten von Programmiersprachen<br />
• Auswahl Sprache und Paradigmen entsprechend der Aufgabe<br />
• Sprachparadigmen imperativ, funktional und logisch<br />
• Programmierparadigmen wie nebenläufiges <strong>Programmieren</strong>/Threading<br />
• Sprachebenen höhere Abstraktion und maschinennah<br />
• Einsatz und Nutzen passender Bibliotheken<br />
Umgang mit praxisrelevanten Sprachen in typischer Umgebung<br />
• Maschinennahes <strong>Programmieren</strong><br />
mit C<br />
• Höheres <strong>Programmieren</strong>/<strong>Skript</strong>en<br />
mit Python<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 4 / 326
Organisatorisches<br />
Maschinennahe Sprachen – C<br />
C, Ansi C<br />
• Maschinennahe Sprache<br />
• Systemnahe Programmierung<br />
• Erstellung von Bibliotheken<br />
• Eigene Speicherverwaltung<br />
• Spartanische,<br />
aber mächtige Entwicklungsumgebung<br />
Inhalt<br />
• Editor<br />
• Kommandozeilentools<br />
• Entwicklungsumgebung Kommandozeile<br />
• Datentypen, Kontrollstrukturen und Funktionen<br />
• Pointer und Speicherverwaltung<br />
• Zeichenkettenverarbeitung<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 5 / 326
Organisatorisches<br />
Ausdrucksstarke höhere Sprachen – Python<br />
Python<br />
• <strong>Skript</strong>sprache<br />
• Anwendungsentwicklung<br />
• Einfach Quellcode zu erstellen,<br />
zu lesen, zu warten<br />
• Interaktiv, viele IDEs<br />
• Integration verschiedener Sprachparadigmen,<br />
Einsatz nach Bedarf/Eleganz<br />
• Imperativ<br />
• Objekt-orientiert<br />
• Funktional<br />
• Einsatz von Bibliotheken: GUI, reguläre Ausdrücke, . . .<br />
Inhalt<br />
• Eingebaute mächtige Datentypen und Kontrollstrukturen<br />
• Funktionales <strong>Programmieren</strong> und Generatoren<br />
• Module und Klassen<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 6 / 326
Organisatorisches<br />
Thread-Programmierung<br />
Nebenläufiges <strong>Programmieren</strong> / Thread-Programmierung<br />
• Mehrere Ausführungsstränge gleichzeitig<br />
innerhalb eines Prozesses eines Anwendungsprogramms<br />
• Zeit sinnvoll nutzen während IO-Operationen<br />
• Nutzen von Mehrkernumgebungen<br />
Inhalt<br />
• Thread-API<br />
• Phänomene und Vermeidung<br />
• Typische Patterns<br />
Wissen 1:1 für Java-Umgebung nutzbar<br />
• In Python/Jython<br />
• Python Thread API wie Java Thread API<br />
Thread<br />
Objekt<br />
Sperre<br />
Objekt<br />
Thread<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 7 / 326
Organisatorisches<br />
Literatur<br />
C<br />
• C als erste Programmiersprache, Dausmann,<br />
Bröckl, Goll[Online verfügbar]<br />
• <strong>Programmieren</strong> in C, (ANSI C),<br />
Brian W. Kernighan, Dennis M. Ritchie<br />
• http://openbook.galileocomputing.de<br />
Python<br />
/c_von_a_bis_z/<br />
• http://www.python.org/doc<br />
• Einführung in Python, Mark Lutz und<br />
David Ascher, O’Reilly, 2. Auflage<br />
• Python Scripting for Computational Science,<br />
Langtangen, Springer<br />
Threading<br />
• Concurrent Programming in Java, Doug Lea<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 8 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Die Programmiersprache C<br />
Seit 1971 für Systemprogrammierung<br />
Ziel<br />
• Entwicklung/Portierung von Betriebssystem (Unix, PDP-7, DEC)<br />
• Statt Assembler, aber Performance vergleichbar mit Assembler<br />
• Hardware-nah, aber doch plattformunabhängig<br />
• Maschinennah, aber strukturierte Programmierung unterstützen<br />
Historie<br />
71: Ritchie, C (Weiterentwicklung von B, BCPL),<br />
Portierung von Unix (nur 10 % Assembler, Rest C)<br />
78: Kernighan & Ritchie, “The C Programming Language”<br />
89: Standardisierung, ANSI-C (Sprache, Bibliotheken),<br />
Überarbeitung C90, heute weit verbreitet<br />
99: C99, Einflüsse C++, noch nicht weit verbreitet<br />
Verwendung<br />
• Systementwicklung, „portabler Assembler“<br />
• Betriebssysteme (z.B. Unix, Linux), Tools (z.B. Shell, gtk)<br />
• Programmiersprachen (z.B. Java, Python, ...)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 9 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Verbreitung von C<br />
Weltweit ist C die meist verwendete Programmiersprache<br />
The C Programming Language<br />
• Klassisches Buch<br />
• Übersetzt in sehr viele Sprachen<br />
• http://cm.bell-labs.com/<br />
cm/cs/cbook/index.html<br />
Programming Language Index<br />
• Juli 2012 wieder die meist<br />
verwendete Sprache<br />
• http://www.tiobe.com/<br />
index.php/content/<br />
paperinfo/<br />
tpci/index.html<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 10 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Eigenschaften von C<br />
Imperativ, hardwarenah und plattformunabhängig<br />
C is declining somewhat in usage compared to C++, and maybe<br />
Java, but perhaps even more compared to higher-level scripting<br />
languages. It’s still fairly strong for the basic system-type things.<br />
Dennis Ritchie<br />
Imperative/Prozedurale Sprache<br />
• Typen, Variablen, Kontrollstrukturen, Funktionen<br />
• Zeiger und Bitoperationen in Sprache integriert, maschinennah<br />
• Kleiner Sprachkern, aber viele Operatoren<br />
• Keine Objektorientierung<br />
(C++ als C-Erweiterung mit OO-Konzepten)<br />
Getrennte Übersetzung<br />
• Übersetzung von Quelldateien in Objektdateien<br />
• Linken der Objektdateien zu ausführbarem Programm<br />
• Kein Modulkonzept, textueller Präprozessor<br />
Plattformunabhängig<br />
• Auf fast jeder Hardware verfügbar<br />
• Programme laufen auf jeder Hardware auf der C läuft,<br />
zumindest wenn man entsprechend programmiert<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 11 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Erstes Beispiel<br />
“Hello World” in C<br />
• Syntax ähnlich zu Java<br />
• Eigentlich umgekehrt<br />
1 Kommentare<br />
• Von /* und */ umschlossen<br />
• Nicht verschachtelt<br />
• Mehrere Zeilen möglich<br />
2 Makros<br />
• Kein Modulkonzept<br />
• Andere Dateien werden inkludiert,<br />
(Inhalt an die Stelle “kopieren”)<br />
• Makroanweisungen mit #...<br />
3 Whitespaces nicht relevant<br />
4 Funktionsdefinitionen<br />
• Eine Hauptfunktion je Programm<br />
• Name ist immer main<br />
1 /* the one and only */<br />
2 #include <br />
3<br />
4 int main(void) {<br />
5 printf("Hello C World\n");<br />
6 return 0;<br />
7 }<br />
5 Funktionsaufrufe<br />
• printf, in stdio.h deklariert<br />
• Mit einem Parameter<br />
6 Rückgabewert<br />
• Hauptfunktion gibt immer einen<br />
Integer-Wert zurück<br />
7 Ende der Funktion<br />
• Einrückregeln wie in Java erlaubt,<br />
andere möglich<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 12 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Übersetzen und Starten<br />
Separate Übersetzung in eine ausführbare Datei<br />
Datei hello.c mit Editor erstellen<br />
• Emacs oder vi empfohlen<br />
• Geany oder auch IDE möglich<br />
Übersetzen mit C-Compiler<br />
• (g)cc, (GNU) C Compiler<br />
• Erzeugt ausführbares Programm,<br />
Datei a.out<br />
Compiler-Optionen -g -ansi -Wall -o<br />
• Debug, ANSI-Standard, Warnung<br />
• Ausgabedatei ist hello<br />
Ausführen<br />
• Aufruf Name erzeugter Datei<br />
• Auf Kommandozeile<br />
• ./ davor wenn . nicht im Pfad<br />
$ ls -l hello.c<br />
-rwx------ 1 pb pb 80<br />
30. Aug 13:33 hello.c<br />
$ gcc hello.c<br />
$ ls -al a.out<br />
-rwx------ 1 pb pb 4699<br />
30. Aug 13:46 a.out<br />
$ ./a.out<br />
Hello C World<br />
$ gcc -g -ansi -Wall hello.c -o hello<br />
$ ls -l ./hello<br />
-rwx------ 1 pb pb 5871<br />
30. Aug 13:47 ./hello<br />
$ ./hello<br />
Hello C World<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 13 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Übersetzungsprozess<br />
Was passiert bei der Übersetzung im Detail<br />
Präprozessor<br />
• Fügt Quelltexte/Include-Dateien ein, Konvention<br />
Endung .h (Header), sucht Dateien in bestimmten<br />
Verzeichnissen /usr/include/...,<br />
• Textuelle Ersetzungen<br />
C-Compiler<br />
• Übersetzt C-Quellcode in hardwarespezifische<br />
Assemblersprache<br />
• Optimierungen<br />
Assembler<br />
• Übersetzt Assembler in Maschinensprache<br />
Linker<br />
• Bindet externen Objektcode ein (z.B. printf), sucht<br />
Bibliotheken in bestimmten Verzeichnissen<br />
/usr/lib/...,<br />
hello.c<br />
gcc hello.c -o hello<br />
Präprozessor<br />
C-Compiler<br />
Assembler<br />
Linker<br />
hello<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 14 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Makefiles<br />
Automatisierung des Übersetzungsprozesses ...<br />
Variablen<br />
1 Definition: CC=gcc<br />
• Verwendung mit $(CC)<br />
• Variablennamen per Konvention<br />
GROßBUCHSTABEN<br />
Regeln<br />
4 Ziel hello und Abhängigkeit hello.c<br />
• Um Ziel zu machen, schaue ob<br />
Abhängigkeit neuer ist als hello, wenn<br />
ja dann mache<br />
5 Führe Befehl (mit Ersetzungen) aus<br />
Verwenden auf Kommandozeile<br />
• Auf Kommandozeile make<br />
• Ziel als Parameter möglich<br />
Makefile<br />
1 CC=gcc<br />
2 CFLAGS=-ansi -g -Wall<br />
3<br />
4 hello: hello.c<br />
5 $(CC) $(CFLAGS) hello.c -o hello<br />
$ make<br />
gcc -ansi -Wall hello.c -o hello<br />
$ ./hello<br />
Hello C World<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 15 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Makefiles<br />
... etwas ausführlicheres Beispiel, Details im Informationsblatt<br />
Ziel all<br />
• Erstes Ziel ist Default-Ziel<br />
• Konvention all<br />
Trennen Compile/Link<br />
• Erst Objekt-Datei mit -c<br />
• Dann Binden/Linken<br />
Beispiel<br />
• Mache rot13 falls rot13.o neuer<br />
• Mache rot13.o falls rot13.c ...<br />
Ziel clean<br />
• Konvention, zum Löschen aller<br />
erzeugten Dateien<br />
• Ohne Abhängigkeit (Datei clean nicht<br />
vorhanden), immer ausführen<br />
Makefile<br />
1 CC=gcc<br />
2 CFLAGS=-ansi -g -Wall<br />
3<br />
4 all: hello rot13<br />
5<br />
6 hello: hello.c<br />
7 $(CC) $(CFLAGS) hello.c -o hello<br />
8<br />
9 rot13.o: rot13.c<br />
10 $(CC) -c $(CFLAGS) rot13.c -o rot13.o<br />
11<br />
12 rot13: rot13.o<br />
13 $(CC) $(CFLAGS) rot13.o -o rot13<br />
14<br />
15 clean:<br />
16 # - vor Befehl, ignoriere Fehlschlag<br />
17 -/bin/rm -f hello rot13 rot13.o<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 16 / 326
<strong>Programmieren</strong> in C<br />
Einführung in C<br />
Java versus C<br />
Objektorientiert<br />
Java<br />
Automatische Speicherverwaltung<br />
Ausnahmen<br />
Aussagekräftige Fehlermeldungen zu<br />
Laufzeit: Zum Beispiel IndexOutOf-<br />
Bounds, NullPointer<br />
Plattformunabhängige auf JVM ausführbare<br />
Dateien<br />
Getrennte Übersetzungseinheiten,<br />
klassenbasiert<br />
Namensräume<br />
String-Typ eingebaut<br />
C<br />
Prozedural, imperativ<br />
Manuelle Speicherverwaltung<br />
keine Ausnahmen, Konvention Fehler-<br />
Codes<br />
Keine Laufzeitfehlermeldungen: Abbruch<br />
durch Betriebssystem oder undefiniertes<br />
Verhalten<br />
Plattformabhängige<br />
Dateien<br />
Getrennte<br />
dateibasiert<br />
Keine Namensräume<br />
ausführbare<br />
Übersetzungseinheiten,<br />
Kein eingebauter String-Typ, Konvention<br />
char-Felder<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 17 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Variablen und Grundtypen<br />
Variablen und Grundtypen fast wie in Java<br />
Lokale Variablen<br />
• Deklaration (oder Vereinbarung) am<br />
Anfang der Funktion<br />
• Viele Compiler erlauben die<br />
Deklaration an beliebiger Stelle, wie in<br />
Java. Erst ab C99 erlaubt, vermeiden.<br />
• Erst Typname dann Variablenname<br />
4 Initialisierung möglich<br />
5 Mehrfachvereinbarung möglich<br />
Ausgabe mit printf<br />
• Konvention wie System.out.format<br />
1 #include <br />
2<br />
3 int main(void) {<br />
4 int i = 3;<br />
5 int j, k;<br />
6 double x = 3;<br />
7 j = 4;<br />
8 printf("%d\n", i+j);<br />
9 printf("%f\n", x*3.3);<br />
10 return 0;<br />
11 }<br />
• Dokumentation mit man 3 printf<br />
7<br />
9.900000<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 18 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Nicht initialisierte lokale Variablen<br />
Nicht initialisierte lokale Variablen haben undefinierten Wert<br />
Nicht initialisierte lokale Variablen<br />
• Deklarierbar und verwendbar<br />
• “Undefinierter” (beliebiger) Wert<br />
in der Variablen k<br />
Compiler/Laufzeit<br />
• Warnung nur bei höchster<br />
Warnstufe<br />
• Ausführung möglich<br />
• Undefiniertes Verhalten<br />
Variablen immer mit Wert initialisieren!<br />
1 #include <br />
2 int main(void) {<br />
3 int j, k;<br />
4 j = 4;<br />
5 printf("%d\n%d\n", j, j+k);<br />
6 return 0;<br />
7 }<br />
$ gcc -Wall ./nichtinit.c -o nichtinit<br />
./nichtinit.c: In Funktion "main":<br />
./nichtinit.c:9:9: Warnung: "k" wird in<br />
Funktion uninitialisiert verwendet<br />
$ ./nichtinit<br />
4<br />
134513308<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 19 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Globale und lokale Variablen<br />
Globale Variablen leben immer und werden initialisiert<br />
Globale/Externe Variablen<br />
• Außerhalb von Funktionen definiert<br />
• Können initialisiert werden<br />
• Wenn nicht explizit initialisiert, werden<br />
sie implizit mit 0 initialisiert<br />
• In allen Funktionen global verfügbar<br />
• In Java nicht vorhanden<br />
Lokale Variablen<br />
• Lebensdauer der Funktion nur<br />
innerhalb eines Blocks<br />
• Innere Variable gleichen Namens<br />
überdeckt äußere<br />
• Wie in Java<br />
• Ohne Initialisierung beliebiger Wert<br />
1 #include <br />
2 int i=3;<br />
3 int j,k;<br />
4 int main(void) {<br />
5 j = 4;<br />
6 printf("%d\n%d\n", j, j+k);<br />
7 { int lokal=3;<br />
8 printf("%d\n", lokal); }<br />
9 /* lokal nicht mehr vereinbart */<br />
10 return 0;<br />
11 }<br />
4<br />
4<br />
3<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 20 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Grundtypen – Ganze Zahlen<br />
Typen<br />
• char, short, int, long<br />
• Alternativen: short int statt short,<br />
long int statt long<br />
Vorzeichen<br />
• Vorsatz unsigned oder signed,<br />
Vorgabe ist signed<br />
• char kann auch unsigned sein,<br />
implementierungsabhängig<br />
Angabe von Werten<br />
• Zusatz mit U für unsigned und<br />
L für long<br />
• Automatisch konvertiert<br />
1 #include <br />
2 int main(void) {<br />
3 char c = 17;<br />
4 short s = 300;<br />
5 int i = 66666;<br />
6 long l = 66666L;<br />
7 return 0;<br />
8 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 21 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Grundtypen – Ganze Zahlen, Größen<br />
Größen-Hierarchie<br />
• char genau 1 Byte groß<br />
• char
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Rechnen mit Zahlen<br />
Ausdrücke<br />
• Operatoren, Präzedenzen, . . . ,<br />
wie von Java gewöhnt<br />
• Modulo-Arithmetik, Zweierkomplement<br />
Typkonversion<br />
• Automatische Konversion aller Werte zu<br />
mindestens int<br />
• Konvertiere danach erst zu Zieltyp<br />
Besonderheit Zuweisung<br />
• Zuweisung ist Ausdruck, Wert ist Wert der rechten<br />
Seite<br />
• = ist rechtsassoziativ<br />
c1 = c2 = 222 entspricht c1 = (c2 = 222)<br />
1 #include <br />
2 int main(void) {<br />
3 unsigned char c1, c2;<br />
4 short s;<br />
5 c1 = c2 = 222;<br />
6 s = c1 + c2;<br />
7 printf("%d\n", s);<br />
8 /* Ausgabe 444 */<br />
9 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 23 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Gleitkommazahlen<br />
Gleitkommanzahlen, Fließpunktzahlen<br />
• float und double als Datentypen wie<br />
in Java<br />
• zusätzlich long double<br />
• float
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Zeichen<br />
Datentyp char<br />
• Ganzzahliger Datentyp<br />
• Steht meist für ein Zeichen<br />
• Meist (trotzdem) signed,<br />
implementierungsabhängig<br />
• Genau ein Byte groß<br />
• Kleinster Datentyp in C<br />
Verwendung<br />
• Ganze Zahlen oder Zeichen<br />
• Zeichen sind ganze Zahlen<br />
• Entsprechung ’A’== 65 abhängig<br />
von Umgebung/Compiler<br />
1 #include <br />
2 int main(void) {<br />
3 char c0 = ’A’;<br />
4 char c1 = 65;<br />
5<br />
6 printf("%c, %c\n", c0, c1);<br />
7 printf("%d, %d\n", c0, c1);<br />
8 printf("%d\n", ’A’*’B’);<br />
9<br />
10 return 0;<br />
11 }<br />
A, A<br />
65, 65<br />
4290<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 25 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Kein Boolean, sondern ganze Zahlen<br />
Kein Boolean in C<br />
• ab C99 _Bool<br />
Ganze Zahlen als Boolescher Ausdruck<br />
• Jede ganze Zahl kann als Boolean<br />
interpretiert werden<br />
• Auch Ausdrücke möglich<br />
• 0 ist falsch,<br />
ungleich 0 ist wahr<br />
Boolesche Ausdrücke evaluieren zu<br />
Zahlen<br />
• Boolesche Ausdrücke (Operatoren)<br />
• Evaluieren zu<br />
0 (falsch) oder 1 (wahr)<br />
1 #include <br />
2 int main(void) {<br />
3 int zahl = 2;<br />
4 if (1)<br />
5 printf("ja1\n");<br />
6 if (zahl)<br />
7 printf("ja2\n");<br />
8 if (zahl-2)<br />
9 printf("ja3\n");<br />
10 printf("%d\n", zahl == 2);<br />
11 return 0;<br />
12 }<br />
ja1<br />
ja2<br />
1<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 26 / 326
<strong>Programmieren</strong> in C<br />
Variablen und Datentypen<br />
Aufzählungstypen<br />
Aufzählung mit enum<br />
• Definition von Konstanten<br />
• Kompatibel zu Typ int<br />
• Durch Komma getrennt<br />
• Optional mit Initialisierung<br />
• Dürfen überall auftauchen wo<br />
Konstanten erwartet werden<br />
(z.B. case in switch-Konstrukt)<br />
Initialisierung<br />
• Erste Konstante 0, wenn nicht<br />
initialisiert<br />
• Nächste Konstante immer um 1 höher,<br />
wenn nicht initialisiert<br />
Achtung: Nicht typsicher, kein<br />
Wertebereichs-Check<br />
1 #include <br />
2 enum skat { karo=9, herz, pik, kreuz };<br />
3 enum farbe { rot, gruen=17, blau };<br />
4<br />
5 int main(void) {<br />
6 enum skat blatt = karo;<br />
7 printf("karo=%d, herz=%d, "<br />
8 "pik=%d, kreuz=%d\n",<br />
9 karo, herz, pik, kreuz);<br />
10 printf("rot=%d, gruen=%d, blau=%d\n",<br />
11 rot, gruen, blau);<br />
12 blatt = 42; /* kein Check*/<br />
13 return 0;<br />
14 }<br />
karo=9, herz=10, pik=11, kreuz=12<br />
rot=0, gruen=17, blau=18<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 27 / 326
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Mengen mit Bitoperationen – Definition<br />
Beispiel für Aufzählungstypen<br />
Idee – Interpretiere Zahlen als Bitfeld<br />
• Shift-Operationen um mit 1
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Mengen mit Bitoperationen – Verwendung<br />
Beispiel für Aufzählungstypen<br />
Beispiel<br />
• Scheine von Rudi und Susi ausgeben<br />
• Susi und Rudi haben von den<br />
möglichen fünf Scheine<br />
• Von denen ist nur einer der Gleiche<br />
• Susi fehlen noch zwei Scheine<br />
Kein Wertebereichs-Check<br />
• Susi |= 0xFFFFFF<br />
• Wäre ok<br />
• Keine Überprüfung ob Wert einer der<br />
Werte des Aufzählungstyps ist<br />
1 int main(void) {<br />
2 enum Scheine Susi =<br />
3 Prog1 | Prog2 | Theo;<br />
4 int Rudi = Prog1 | Prog3 | ADS;<br />
5<br />
6 printschein(Susi);<br />
7 printschein(Rudi);<br />
8 printschein(Susi|Rudi);<br />
9 printschein(Susi&Rudi);<br />
10 printschein(~Susi);<br />
11 return 0;<br />
12 }<br />
Prog1 Prog2 Theo<br />
Prog1 Prog3 ADS<br />
Prog1 Prog2 Prog3 ADS Theo<br />
Prog1<br />
Prog3 ADS<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 29 / 326
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Variablen Definition und Deklaration<br />
Variablen Definition<br />
• Legt Typ fest<br />
• Reserviert Speicherplatz<br />
• Darf nur einmal vorkommen<br />
• Syntax wie gewohnt,<br />
global und lokal<br />
Variablen Deklaration<br />
• Legt Typ fest<br />
• Darf mehrmals vorkommen<br />
• Schlüsselwort extern davor,<br />
muss global sein<br />
Definition = Deklaration + Speicherplatz<br />
1 extern int exta; /* Deklaration */<br />
2 int main(void) {<br />
3 return exta;<br />
4 }<br />
5 /* Fehler, exta nicht definiert */<br />
1 extern int exta; /* Deklaration */<br />
2 extern int exta; /* Deklaration */<br />
3<br />
4 int exta = 3; /* Definition */<br />
5<br />
6 /* int exta = 3; Fehler Redefinition */<br />
7<br />
8 int main(void) {<br />
9 extern int exta; /* Deklaration */<br />
10 extern int exta; /* Deklaration */<br />
11 /* int exta; lokal nicht erlaubt */<br />
12 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 30 / 326
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Typ-Attribute – konstant<br />
Konstantenvereinbarung<br />
• Schlüsselwert const<br />
• Wert darf nicht verändert werden<br />
• Definition ohne Wert möglich (leider),<br />
Vorgabewert ist 0<br />
• extern möglich, muss dann später als<br />
const definiert werden<br />
Verwendung von const im Parametertyp<br />
• Wert darf dann in Funktion nicht<br />
verändert werden<br />
• Da Werte kopiert werden, sind<br />
Änderungen an z.B. einem int<br />
sowieso nur lokal<br />
#define nicht verwenden<br />
• Nicht typsicher, nicht Teil von C<br />
1 #define PI 3.14 /* boese */<br />
2<br />
3 const double pi = 3.14;<br />
4<br />
5 const int len=7+3;<br />
6<br />
7 extern const int c;<br />
8 const int c=3;<br />
9<br />
10 int f(void) {<br />
11 /* c = 4; Fehler */<br />
12 return c;<br />
13 }<br />
14<br />
15 int f2(const int i) {<br />
16 /* i = 4; Fehler */<br />
17 return i;<br />
18 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 31 / 326
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Typ-Attribute – const statt #define<br />
Präprozessor #define<br />
• Textersetzung, Text nach ersten<br />
Whitespaces durch Text nach zweiten<br />
Whitespaces<br />
• Keine Ersetzung in Zeichenketten und<br />
innerhalb von Bezeichnern<br />
• Alter Stil, als es const noch nicht gab<br />
• Nicht typsicher, tückisch, vermeiden<br />
Konstanten mit const<br />
• Definition einer Variablen mit<br />
konstantem Inhalt<br />
• Typsicher, Klar, verwenden<br />
enum für int-Konstanten<br />
• Wenn const nicht geht (z.B.<br />
Feldgrenzen), dann enum verwenden<br />
1 #include <br />
2<br />
3 #define PI 3.14<br />
4 const double pi = 3.14;<br />
5<br />
6 double umfangc(double radius) {<br />
7 return 2*pi*radius;<br />
8 }<br />
9 double umfangd(double radius) {<br />
10 return 2*PI*radius;<br />
11 }<br />
12<br />
13 #define LEN 7+3<br />
14 const int len=7+3;<br />
15<br />
16 int main(void) {<br />
17 printf("%3d\n", LEN*3); /* 16 */<br />
18 printf("%3d\n", len*3); /* 30 */<br />
19 return 0;<br />
20 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 32 / 326
<strong>Programmieren</strong> in C<br />
Bitoperationen<br />
Typ-Attribute – volatil<br />
Variable ändert sich “von außen”<br />
• Variable kann sich ohne Einwirkung<br />
des laufenden Programms ändern<br />
• Beispiel: Treiber für eine Hardware,<br />
die Ihren Zustand nicht auf Grund von<br />
Programmabläufen ändert<br />
• Gewünschtes Verhalten:<br />
• Compiler soll keine Optimierungen<br />
(Eliminiation aus Ausdrücken,<br />
Umordnung von Code) vornehmen<br />
• Wert muss jedesmal aus<br />
Speicherbereich gelesen werden<br />
volatil-Vereinbarung<br />
• Schlüsselwort volatile<br />
1 #include <br />
2<br />
3 int main(void) {<br />
4 volatile int x=3;<br />
5 int i, s=0;<br />
6 for (i=0; i < 1000; i+=1) {<br />
7 /* x wird immer hier neu gelesen */<br />
8 s += x*i;<br />
9 }<br />
10 return 0;<br />
11 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 33 / 326
<strong>Programmieren</strong> in C<br />
Eingabe und Ausgabe<br />
Ausgabe<br />
printf<br />
• Gibt 1. Parameter auf Standardausgabe aus<br />
Aufeinanderfolgende Strings werden zu einem<br />
zusammengefasst – vermeiden<br />
• Ersetzt alle %-Konstrukte in 1. Parameter durch<br />
jeweils nächsten Wert in den weiteren Parametern<br />
• Wie System.out.format, beliebig viele Parameter<br />
sprintf<br />
• Zusätzlicher 1. Parameter<br />
• In diesen String (1. Parameter) wird geschrieben statt<br />
Ausgabe nach stdout<br />
• Achtung: String muss lang genug sein<br />
putchar<br />
• Gibt Paramter (int nicht char) auf stdout aus<br />
• Erlaubt Ausgabe von Steuerzeichen (EOF, . . . )<br />
1 #include <br />
2 int main(void) {<br />
3 int d=42;<br />
4 char c=’a’;<br />
5 double g=3.14;<br />
6 printf(<br />
7 "int: %d\n"<br />
8 "char: %c\n"<br />
9 "double: %e\n",<br />
10 d, c, g);<br />
11 return 0;<br />
12 }<br />
int: 42<br />
char: a<br />
double: 3.140000e+00<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 34 / 326
<strong>Programmieren</strong> in C<br />
Eingabe und Ausgabe<br />
Eingabe<br />
scanf<br />
• Liest Zeichen von der Standardeingabe<br />
• Wie in 1. Parameter verlangt<br />
• Im Beispiel ist das Leerzeichen in der Eingabe wichtig<br />
• Bei %-Konstrukten wird entsprechender Wert erzeugt<br />
• Wert wird an die Adresse der Variablen (Notation mit<br />
&-Zeichen) gespeichert<br />
• Rückgabewert ist die Anzahl der erfolgreich<br />
eingelesenen Werte<br />
• Bei Fehlern geht es undefiniert weiter<br />
sscanf<br />
• Neuer erster Parameter, der Eingabestring<br />
• Eingabestring statt Lesen von stdin<br />
1 #include <br />
2<br />
3 int main(void) {<br />
4 int d;<br />
5 char c;<br />
6 double g;<br />
7 scanf("%d %c %lg",<br />
8 &d, &c, &g);<br />
9 printf("int: %d\n"<br />
10 "char: %c\n"<br />
11 "double:%e\n",<br />
12 d, c, g);<br />
13 return 0;<br />
14 }<br />
>> 42 a 3.14<br />
<strong>Programmieren</strong> in C<br />
Eingabe und Ausgabe<br />
Eingabe zeichenweise<br />
getchar<br />
• Ein Zeichen von stdin lesen<br />
• Wert ist Zeichen als int<br />
• Steuerzeichen möglich, zum Beispiel<br />
EOF am Ende einer Datei oder der<br />
Eingabe<br />
Beispiel: Eingabe auf Ausgabe kopieren<br />
• Zeichenweises einlesen von der<br />
Standardeingabe bis<br />
Dateiendezeichen (CTRL-D)<br />
• Zuweisung in Test, typisches Idiom<br />
1 #include <br />
2<br />
3 int main() {<br />
4 int c;<br />
5 while ((c = getchar()) != EOF) {<br />
6 putchar(c);<br />
7 }<br />
8 return 0;<br />
9 }<br />
• putchar als Gegenstück zu getchar<br />
• getc zur Angabe eines<br />
Eingabe-Stroms<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 36 / 326
<strong>Programmieren</strong> in C<br />
Eingabe und Ausgabe<br />
%-Konstrukte<br />
%-Konstrukte für ganze Zahlen<br />
• char: %c, int: %d, %i<br />
• unsigned int: %u dezimal, %o oktal,<br />
%x hexadezimal<br />
• long int: %ld, %li,<br />
short int: %hd, %hi<br />
%-Konstrukte Gleitkommenzahlen<br />
• float: %f(x.xx), %e(x.xxEyy), %g<br />
double: %lf(x.xx), %le(x.xxEyy), %lg<br />
• Modifier l nur bei Eingabe relevant,<br />
Ausgabe wird immer erst mindestens<br />
double<br />
Dokumentation<br />
• Mit man printf, man scanf<br />
• Gewöhnen Sie sich an man<br />
1 #include <br />
2 int main() {<br />
3 unsigned int d = 17;<br />
4 double f = 3.14;<br />
5<br />
6 printf("%%u: %u, %%o: %o, %%x: %x\n",<br />
7 d, d, d);<br />
8 printf("%%f: %f, %%e: %e, %%g: %g\n",<br />
9 f, f, f);<br />
10 f = 1.000000000000001;<br />
11 printf("%20.20f\n%20.20f\n",<br />
12 f, (float) f);<br />
13 return 0;<br />
14 }<br />
%u: 17, %o: 21, %x: 11<br />
%f: 3.140000, %e: 3.140000e+00, %g: 3.14<br />
1.00000000000000111022<br />
1.00000000000000000000<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 37 / 326
<strong>Programmieren</strong> in C<br />
Kontrollstrukturen<br />
Kontrollstrukturen wie in Java<br />
Bedingungen<br />
• Beliebige arithmetische Ausdrücke<br />
• Logische Operatoren geben 0 oder 1<br />
zurück<br />
Verzweigung<br />
• wie gewohnt<br />
• if, else, switch, break<br />
Schleifen<br />
• while, do while, break, continue<br />
• for<br />
anfang 0<br />
anfang 1<br />
anfang 0<br />
• Keine Variablenbelegung in for<br />
• Erlaubt ab C99<br />
1 #include <br />
2 int main(void) {<br />
3 int i;<br />
4 for (i=0; i < 3; i++) {<br />
5 int j=2, k=0;<br />
6 while (j)<br />
7 j--;<br />
8 j = 1
<strong>Programmieren</strong> in C<br />
Funktionen<br />
Funktionen<br />
Funktionsdefinition ähnlich zu Java<br />
• Auf oberster Ebene<br />
• Nicht geschachtelt<br />
Parameter<br />
• Parameter werden als Werte<br />
übergeben (call by value)<br />
• Keine Parameter mit (void)<br />
• Nur () veraltet, vermeiden<br />
• Beliebig viele Parameter mit (...)<br />
• prinf ist so definiert<br />
• Wird nicht weiter behandelt<br />
• Überladen ist nicht möglich<br />
Rückgabewert<br />
• Typ angeben (Vorgabe int, veraltet)<br />
• void für kein Rückgabewert<br />
1 #include <br />
2<br />
3 int f(void) {<br />
4 return 0;<br />
5 }<br />
6<br />
7 int inc(int i) {<br />
8 return i+1;<br />
9 }<br />
10<br />
11 int summiere(int i0, int i1) {<br />
12 return i0 + i1;<br />
13 }<br />
14<br />
15 int main(void) {<br />
16 int i = inc(3);<br />
17 return summiere(i, -i);<br />
18 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 39 / 326
<strong>Programmieren</strong> in C<br />
Funktionen<br />
Funktionsprototypen<br />
Problem – Benutzung vor Definition<br />
• Funktion wird verwendet, bevor sie definiert wurde<br />
• Andere Reihenfolge ist keine Lösung bei<br />
verschränkter Rekursion (odd, even)<br />
Lösung – Funktionsprototypen<br />
• Kopf der Funktion, Zeile 3<br />
• Ohne definierenden Block, mit Semikolon,<br />
Parameternamen dürfen fehlen<br />
• Funktion wird deklariert, noch nicht definiert<br />
• Angabe von extern davor erlaubt<br />
• extern int even(short int i);<br />
• Bekanntgabe des Rückgabewerts und des Typs des<br />
Parameters<br />
• Ohne Prototypen im Beispiel Übersetzungsfehler<br />
• Schlimmer wäre implizite Deklaration<br />
int even();<br />
1 #include <br />
2<br />
3 int even(short int i);<br />
4 int odd(short int i) {<br />
5 if (i == 0)<br />
6 return 0;<br />
7 return even(i-1);<br />
8 }<br />
9 int even(short int i) {<br />
10 if (i == 0)<br />
11 return 1;<br />
12 return odd(i-1);<br />
13 }<br />
14<br />
15 int main(void) {<br />
16 short int i = 17;<br />
17 printf("%d ist %s\n", i,<br />
18 odd(i) ? "odd" : "even");<br />
19 return 0;<br />
20 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 40 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Felder<br />
Feld<br />
• Speicherbereich mit mehreren gleich<br />
großen Elementen eines Typs<br />
• Zusammenhängender<br />
Speicherbereich<br />
Felder anlegen<br />
• Definition mit<br />
[]<br />
• Die Länge des Felds ist ein konstanter<br />
Ganzzahlausdruck, Angabe mit<br />
enum-Wert erlaubt<br />
• Ab C99 darf Länge eine Variable sein<br />
• In GCC erlaubt, nicht verwenden<br />
• Index von 0 bis -1<br />
Beispiel: 10 int Werte<br />
int a[10];<br />
0 1 2 3 4 5 6 7 8 9<br />
enum { G=10 };<br />
...<br />
int a[G];<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 41 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Feldgröße<br />
Größe des Felds<br />
• Anzahl der Elemente mal Größe je<br />
Element<br />
• Gesamtgröße außerhalb des Blocks<br />
der Definition nicht verfügbar<br />
Beispiel<br />
• im Gegensatz zu Java<br />
• 10 Mal ein int der Größe 4,<br />
also 40 Byte<br />
• Bei Funktion f mit Feld als Parameter<br />
ist die verfügbar Größe nur die Größe<br />
des Zeigers (später)<br />
1 #include <br />
2 void f(int a[10]) {<br />
3 printf("in f : %ld\n", sizeof a);<br />
4 }<br />
5 int main(void) {<br />
6 int a[10];<br />
7 printf("in main: %ld\n", sizeof a);<br />
8 f(a);<br />
9 return 0;<br />
10 }<br />
in main: 40<br />
in f : 4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 42 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Auf Feldelemente zugreifen<br />
Zugriff mit []<br />
• Erlaubt von Index 0 bis Länge-1<br />
• Verwendung auf linker und rechter<br />
Seite der Zuweisung (=)<br />
• Wie in Java<br />
Beispiel<br />
• Initialisierung des Felds mit<br />
Quadratzahlen<br />
• Berechnung der Summe der ersten<br />
G-1 Quadratzahlen in Funktion<br />
sum=285<br />
1 #include <br />
2 enum { G=10 };<br />
3 int dosum(int a[], int length) {<br />
4 int sum=0, i;<br />
5 for(i=0; i < length; i++) {<br />
6 sum += a[i];<br />
7 }<br />
8 return sum;<br />
9 }<br />
10 int main(void) {<br />
11 int a[G], i;<br />
12 for(i=0; i < G; i++) {<br />
13 a[i] = i*i;<br />
14 }<br />
15 printf("sum=%d\n", dosum(a, G));<br />
16 return 0;<br />
17 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 43 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Zugriff außerhalb der Feldgrenzen<br />
Feldgrenzen<br />
• Keine Überprüfung der Feldgrenzen<br />
• Zugriff zunächst erlaubt<br />
• Verhalten außerhalb der Feldgrenzen<br />
undefiniert<br />
• Nicht wie in Java,<br />
keine Laufzeitumgebung wie in Java<br />
Fehlerverhalten<br />
• Es geht meistens schief<br />
• Meistens, aber nicht immer<br />
• (viel schlimmer) Nicht immer sofort<br />
• Bei Ausführung Programmabbruch<br />
durch Betriebssystem möglich<br />
(Speicherzugriffsfehler)<br />
• Tools wie valgrind helfen<br />
1 int main(void) { /* felderbumm.c */<br />
2 int a[30];<br />
3 a[30000] = 0;<br />
4 }<br />
Speicherzugriffsfehler<br />
1 int main(void) { /* feldernbumm.c */<br />
2 int a[30];<br />
3 a[1000] = 0;<br />
4 }<br />
% valgrind ./feldernbumm<br />
== Memcheck, a memory error detector<br />
== Invalid write of size 4<br />
== at 0x4004BC: main (feldernbumm.c:3)<br />
== Address 0x7ff0012f0 is not stack’d,<br />
malloc’d or (recently) free’d<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 44 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Felder kopieren<br />
Feldname<br />
• Kann verwendet werden als Konstante<br />
mit Adresse des ersten Feldelements<br />
• Insbesondere als Funktionsparameter<br />
nicht Feld sondern Adresse des Felds<br />
• Ändern der Feldinhalte möglich<br />
Kopieren?<br />
• Durch Zuweisung nicht möglich<br />
• In Java Zuweisung der Referenz<br />
• Bei Feld als Parameter werden dann<br />
Adressen kopiert<br />
• Nicht unbedingt was man will<br />
Richtig kopieren<br />
• Feldweise, wie in Java<br />
• Genauso bei Vergleich, Ausgabe, etc.<br />
1 #include <br />
2<br />
3 int main(void) {<br />
4 int a[30], b[30], i;<br />
5 /* a = b; nicht erlaubt */<br />
6 if (a == b)<br />
7 printf("NIE\n");<br />
8 for (i=0; i < 30; i++) /* init */<br />
9 a[i] = 0;<br />
10 for (i=0; i < 30; i++) /* copy */<br />
11 b[i] = a[i];<br />
12 return 0;<br />
13 }<br />
14<br />
15 void f(int x[30], int y[30]) {<br />
16 x = y; /* erlaubt aber sinnlos */<br />
17 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 45 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Mehrdimensionale Felder<br />
Definieren mehrdimensionaler Felder<br />
• Definition durch Angabe weiterer<br />
Dimensionen<br />
• [3][5] nicht [3,5]<br />
• Größe entspricht Grundgröße mal<br />
Produkt der Dimensionen<br />
• Immer noch ein zusammenhängender<br />
Speicherbereich<br />
Struktur<br />
• Zeilenweise (row major)<br />
• Letzter Index läuft am schnellsten<br />
Beispiel<br />
• Feld a von 3 Zeilen mit je 5 Zahlen<br />
• Insgesamt (3 · 5) · 4 = 60 Byte<br />
1 int a[3][5], i, j;<br />
2 printf("%lu\n", sizeof a);<br />
3 for (i=0; i < 3; i++) {<br />
4 for (j=0; j < 5; j++)<br />
5 a[i][j] = i*5+j;<br />
6 }<br />
7 for (i=0; i < 3; i++) {<br />
8 for (j=0; j < 5; j++)<br />
9 printf("%2d ", a[i][j]);<br />
10 printf("\n");<br />
11 }<br />
0 1 2 3 4<br />
5 6 7 8 9<br />
10 11 12 13 14<br />
60<br />
0 1 2 3 4<br />
5 6 7 8 9<br />
10 11 12 13 14<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 46 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Mehrdimensionale Felder als Parameter<br />
Problem – Dimensionen notwendig<br />
• Dimensionen notwendig um Position in<br />
Speicherbereich zu bestimmen<br />
• Alle Dimensionen außer der Ersten<br />
Zwang Angabe Dimensionen<br />
• Alle Dimensionen außer der Ersten<br />
müssen angegeben werden<br />
• Wenn nicht, dann Fehler<br />
• Alle Dimensionen außer der Ersten<br />
müssen stimmen<br />
Beispiel<br />
• Wenn nicht, dann Warnung<br />
• g1 ist ok<br />
• g2 ist nicht ok<br />
• Bei a fehlt die zweite Dimension<br />
• Bei b fehlt die zweite Dimension<br />
10<br />
1 void g1(int a[][5], int b[3][5],<br />
2 int c[10][5]) {<br />
3 printf("%2d %2d %2d\n",<br />
4 a[1][0], b[1][0], c[1][0]);<br />
5 printf("%2ld %2ld %2ld\n",<br />
6 &a[2][0] - &a[0][0],<br />
7 &b[2][0] - &b[0][0],<br />
8 &c[2][0] - &c[0][0]);<br />
9 }<br />
11 /* Fehler<br />
12 void g2(int a[3][], int b[][]) {} */<br />
0 1 2 3 4<br />
5 6 7 8 9<br />
10 11 12 13 14 5 5 5<br />
10 10 10<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 47 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Initialisierung von Feldern<br />
Initialisierungswerte mit {}<br />
• Funktioniert für eindimensionale und<br />
mehrdimensionale Felder<br />
• Es wird zeilenweise weiter aufgefüllt<br />
• Warnung bei modernen Compilern<br />
• Falls Elemente fehlen, dann werden<br />
diese mit 0 initialisiert<br />
Größe<br />
• Falls Dimension fehlt, dann so viele<br />
wie benötigt<br />
• Nur erste Dimension darf fehlen, die<br />
wird dann berechnet anhand der<br />
Initialisierungswerte<br />
• Keine dynamischen Feldgrößen!<br />
1 int a1[3][5] = { {0,1,2,3,4},<br />
2 {5,6,7,8,9},<br />
3 {10,11,12,13,14} };<br />
4 int a2[][5] = { 0,1,2,3,4,<br />
5 5,6,7,8,9,<br />
6 10,11,12,13,14 };<br />
7 char a3[5] = {1,2,3};<br />
8 int a4[] = {1,2,3};<br />
9 gibaus(a1); /* Ausgabe als Block */<br />
10 gibaus(a2); /* Wie schon angegeben */<br />
11 printf("%2d %2d %2d %2d %2d \n",<br />
12 a3[0], a3[1], a3[2], a3[3], a3[4]);<br />
13 printf("%lu \n", sizeof a4);<br />
0 1 2 3 4<br />
5 6 7 8 9<br />
10 11 12 13 14<br />
...<br />
1 2 3 0 0<br />
12<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 48 / 326
<strong>Programmieren</strong> in C<br />
Felder<br />
Zeichenketten<br />
Kein Zeichenketten-Typ in C!<br />
• Kein dedizierter Typ<br />
• Es wird ein char-Feld verwendet<br />
• Konvention<br />
• Zeichenkette wird mit Zeichen ’\0’<br />
(der Wert 0) abgeschlossen<br />
Keine Operatoren auf Zeichenketten<br />
• Kein kopieren, vergleichen,<br />
konkatenieren, . . .<br />
Bibiliotheken<br />
• Operationen sind Teil der<br />
Standardbibliothek<br />
• string.h, man 3 string<br />
• Verwendung mit Funktionsaufrufen<br />
Beispiel Zeile 8, kein Platz, trotzdem<br />
1 char s1[6] = "Hallo";<br />
2 char s2[11] = "Hallo";<br />
3 char s3[] = "Hallo";<br />
4 char s4[] = {’H’, ’a’, ’l’,<br />
5 ’l’, ’o’, ’\0’ };<br />
6 printf("%s %s %s %s\n", s1, s2, s3, s4);<br />
7 strcat(s2,s1);<br />
8 strcat(s3,s1);<br />
9 printf("%s", s2);<br />
s1 H a l l o \0<br />
s2 H a l l o \0 \0 \0 \0 \0 \0<br />
H a l l o \0<br />
s3 H a l l o \0<br />
H a l l o \0<br />
s4 H a l l o \0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 49 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Getrennte Übersetzung<br />
Größere Softwareprojekte<br />
• Alles in einer Datei nicht mehr sinnvoll<br />
• Keine Modularisierung, keine Pakete<br />
• Was tun?<br />
a.h<br />
#include<br />
b.h<br />
Getrennte Übersetzung<br />
• Getrennte Quell-Dateien, .c<br />
• Header-Dateien,<br />
• .h, mit #include verwenden<br />
• Typinformation, Prototypen, extern<br />
• Separat übersetzen<br />
• -c, nur übersetzen, nicht binden<br />
• Erstellt Objekt-Dateien, .o<br />
• Binden (linken)<br />
• Alle notwendigen Objekt-Dateien,<br />
Abhängigkeiten auflösen<br />
• Ausführbares Programm erzeugen<br />
a.c m.c b.c<br />
$ gcc -c a.c -o a.o<br />
a.o m.o b.o<br />
$ gcc a.o b.o c.o -o m<br />
m<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 50 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Getrennte Übersetzung – Beispiel Fibonacci/1<br />
Separate Fibonacci-Berechnung<br />
• Zwei Methoden, einmal rekursiv<br />
(fibr), einmal iterativ (fibi)<br />
• Gleiche Signatur, von/nach<br />
unsigned int<br />
Separate Datei, fibs.c<br />
• Übersetzung mit -c erzeugt fibs.o<br />
gcc -c fibs.c -o fibs.o<br />
• Die Symbole fibr und fibi werden<br />
bereit gestellt<br />
fibs.o<br />
<<br />
> fibr, fibi<br />
fibs.c<br />
1 unsigned int fibr(unsigned int n) {<br />
2 if ((n == 0) || (n == 1))<br />
3 return n;<br />
4 return fibr(n-1) + fibr(n-2);<br />
5 }<br />
6<br />
7 unsigned int fibi(unsigned int n) {<br />
8 unsigned int f0, f1 = 1, f2 = 0;<br />
9 if ((n == 0) || (n == 1))<br />
10 return n;<br />
11 while (--n) {<br />
12 f0 = f1+f2;<br />
13 f2 = f1;<br />
14 f1 = f0;<br />
15 }<br />
16 return f0;<br />
17 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 51 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Getrennte Übersetzung – Beispiel Fibonacci/2<br />
Verwenden<br />
• Prototypen, damit Typ stimmt<br />
• Aufruf der Funktion<br />
Übersetzen, wie fibs.c<br />
• Die Symbole fibr, fibi und printf<br />
werden benötigt<br />
• Das Symbol main wird bereit gestellt<br />
Binden (linken)<br />
• Alle Objekt-Dateien werden<br />
zusammengeklebt<br />
• gcc fibs.o fib.o -o fib<br />
• main als Start benötigt<br />
• printf in Standardbibliothek<br />
Ausführen: fib(10) = 55 = 55<br />
fib.c<br />
1 #include <br />
2 unsigned int fibr(unsigned int);<br />
3 unsigned int fibi(unsigned int);<br />
4<br />
5 int main(void) {<br />
6 const unsigned int n = 10;<br />
7 printf("fib(%d) = %d = %d\n",<br />
8 n, fibr(n), fibi(n));<br />
9 return 0;<br />
10 }<br />
fib.o<br />
< fibr, fibi,<br />
printf<br />
> main<br />
fibs.o<br />
<<br />
> fibr, fibi<br />
fib<br />
< main<br />
> printf<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 52 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Header-Dateien<br />
Problem – Mehrfachangabe Prototypen<br />
an jedem Vorkommen in der Anwendung<br />
Lösung – Header-Dateien<br />
• Endung per Konvention mit .h<br />
• Auslagern der Prototypen und extern<br />
Deklaration der Variablen<br />
Verwendung<br />
• Einbinden mit #include<br />
• Bei “ im aktuellen Verzeichnis, bei <<br />
nur im Systemverzeichnis<br />
Vorteile<br />
• Mit -I Suchpfad anpassbar<br />
• Wiederverwendbare Module<br />
• Schneller, nur Teile neu übersetzen<br />
• Paralleles Arbeiten einfacher möglich<br />
fibs.h<br />
1 unsigned int fibr(unsigned int);<br />
2 unsigned int fibi(unsigned int);<br />
fib.c<br />
1 #include <br />
2 #include "fibs.h"<br />
3 int main(void) {<br />
4 const unsigned int n = 10;<br />
5 printf("fib(%d) = %d = %d\n",<br />
6 n, fibr(n), fibi(n));<br />
7 return 0;<br />
8 }<br />
fibs.c<br />
1 #include "fibs.h"<br />
2 unsigned int fibr(unsigned int n) {<br />
3 ...<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 53 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Mehrfachinklusion<br />
Mehrfachinklusion bei großen Projekten<br />
• Header-Dateien inkludieren andere,<br />
die wieder andere Header-Dateien<br />
inkludieren<br />
• Dabei kann es passieren, dass eine<br />
Header-Datei mehrfach inkludiert wird<br />
Probleme<br />
• Schlimmstenfalls führt dies zu Fehlern<br />
bei der Übersetzung<br />
• Problematische<br />
Mehrfachvereinbarung zum Beispiel<br />
bei enum<br />
• Endlos-Inklusion falls ursprüngliche<br />
Datei wieder inkludiert wird<br />
• Auf alle Fälle unnötig lange<br />
Übersetzungszeit<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 54 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Präprozessor<br />
Präprozessor<br />
• Inkludieren mit #include<br />
• Textersetzungen mit #define<br />
• Tests mit #ifdef, #ifndef, #else<br />
Umsetzung<br />
• Ausführen der Ersetzungen vor dem<br />
eigentlichen Übersetzen<br />
• Zwischenergebnis nach Ersetzung<br />
mit Option -E<br />
gcc -E prepro.c > prepro.txt<br />
Einsatzgebiet<br />
• Für Konstanten vermeiden<br />
• Für Include-Guards verwenden<br />
1 #include <br />
2 #define TOLLE "SUPER"<br />
3 #define OK 0<br />
4 int main(void) {<br />
5 printf("Hallo %s TOLLE Welt\n", TOLLE);<br />
6 #ifdef TOLLE<br />
7 printf("Es ist was definiert\n");<br />
8 #else<br />
9 printf("Nix is");<br />
10 #endif<br />
11 return OK;<br />
12 }<br />
# 1 "prepro.c"<br />
# [ ... > 800 Zeilen ...]<br />
int main(void) {<br />
printf("Hallo %s TOLLE Welt\n", "SUPER")<br />
printf("Es ist was definiert\n");<br />
return 0;<br />
}<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 55 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Include-Guards<br />
Ziel: Vermeide Mehrfach-Inklusion<br />
• Wenn eine Header-Datei schon<br />
einmal inkludiert wurde,<br />
• Dann inkludiere sie nicht mehr<br />
• Es kann nicht sinnvoll sein<br />
• Deklarationen reichen einmal<br />
Lösung: Include-Guard<br />
• Definiere eine Konstante<br />
• Konvention Dateiname groß, Sonderzeichen<br />
durch Unterstrich ersetzt<br />
• Prüfe ob Konstante nicht definert ist<br />
• Berücksichtige Inhalte nur, wenn diese<br />
Konstate nicht definiert ist<br />
• Effekt: Nur bei ersten Mal wird Inhalt<br />
berücksichtigt<br />
fibs.h<br />
1 #ifndef FIBS_H<br />
2 #define FIBS_H<br />
3<br />
4 unsigned int fibr(unsigned int);<br />
5 unsigned int fibi(unsigned int);<br />
6<br />
7 #endif<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 56 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Beispiel Mehrfachinklusion mit Include-Guards – Schalter/1<br />
zustaende.h<br />
1 #ifndef ZUSTAENDE_H<br />
2 #define ZUSTAENDE_H<br />
3 enum zustand {aus, an};<br />
4 extern enum zustand initial;<br />
5 #endif<br />
zustaende.c<br />
1 #include "zustaende.h"<br />
2 enum zustand initial = aus;<br />
reset.h<br />
1 #include "zustaende.h"<br />
2 enum zustand reset(void);<br />
wechsel.h<br />
1 #include "zustaende.h"<br />
2 enum zustand wechsel(<br />
3 enum zustand aktuell);<br />
reset.c<br />
1 #include "reset.h"<br />
2 static int zaehler=0;<br />
3 static int f(void);<br />
4 enum zustand reset(void) {<br />
5 zaehler += 1+f();<br />
6 return initial;<br />
7 }<br />
8 static int f(void) { return 0; }<br />
wechsel.c<br />
1 #include "wechsel.h"<br />
2 static int zaehler=0;<br />
3 static int f(void);<br />
4 enum zustand wechsel(<br />
5 enum zustand aktuell) {<br />
6 zaehler += 1+f();<br />
7 return (aktuell == an) ? aus : an;<br />
8 }<br />
9 static int f(void) { return 0; }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 57 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Beispiel Mehrfachinklusion mit Include-Guards – Schalter/2<br />
Aufbau<br />
• Wir modellieren einen Schalter<br />
• zustand.h wird von allen gebraucht<br />
• zustand.h wird von reset.h und<br />
wechsel.h inkludiert<br />
• Das Hauptprogramm schalter<br />
resetted und schaltet und inkludiert<br />
entsprechend<br />
Problem<br />
• Mehrfachinklusion in einer<br />
Übersetzungsheit von zustand.h<br />
• Übersetzungsfehler<br />
Mehrfachvereinbarung enum zustand<br />
Lösung: Inlcude-Guard verhindert<br />
Mehrfachinklusion<br />
schalter.c<br />
1 #include <br />
2 #include "reset.h"<br />
3 #include "wechsel.h"<br />
4<br />
5 int main(void) {<br />
6 enum zustand schalter;<br />
7 schalter = reset();<br />
8 printf("%u\n", schalter);<br />
9 schalter = wechsel(schalter);<br />
10 printf("%u\n", schalter);<br />
11 return 0;<br />
12 }<br />
Include-Guards<br />
In jeder Header-Datei immer verwenden.<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 58 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Beispiel Mehrfachdefinition<br />
Problem, Zeile 4<br />
• Definition in einer Header-Datei<br />
• Extrem böse!<br />
• Nie, nie, nie machen<br />
• Da hilft auch kein Include-Guard<br />
Fehlerauftreten<br />
• Sobald Header-Datei in zwei<br />
verschiedenen Übersetzungseinheiten<br />
verwendet wird<br />
• Zweimal Speicherplatz reserviert für<br />
das gleiche Symbol<br />
Doppelt definiertes Symbol<br />
Vermeiden<br />
• In Header-Datei nur deklarieren<br />
• nie definieren<br />
zustaende.h<br />
1 #ifndef ZUSTAENDE_H<br />
2 #define ZUSTAENDE_H<br />
3 enum zustand {aus, an};<br />
4 enum zustand initial=an;<br />
5 #endif<br />
reset.o<br />
< ..<br />
> initial<br />
schalter.o<br />
< ..<br />
> initial<br />
wechsel.o<br />
< ..<br />
> initial<br />
Mehrfach definiertes Symbol initial<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 59 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Namenskollision und static<br />
Namenskollision<br />
• Situation: In zwei Quelldateien (.c<br />
Übersetzungseinheiten) wird zufällig<br />
der gleiche globale Name verwendet<br />
• Effekt: Das Binden geht schief (doppelt<br />
definiertes Symbol), die Variable kann<br />
von überall manipuliert werden<br />
Lösung – static<br />
• static definierte Variable auf globaler<br />
Ebene ist nur lokal für die<br />
Übersetzungseinheit definiert<br />
• Variable ist nicht sichtbar in anderen<br />
Übersetzungseinheiten<br />
• Gleicher Name darf mehrfach<br />
vorkommen<br />
• Dito für static definierte Funktionen<br />
wechsel.c<br />
1 #include "wechsel.h"<br />
2 static int zaehler=0;<br />
3 static int f(void);<br />
4 enum zustand wechsel...<br />
5 static int f(void) { return 0; }<br />
reset.c<br />
1 #include "reset.h"<br />
2 static int zaehler=0;<br />
3 static int f(void);<br />
4 enum zustand reset...<br />
5 static int f(void) { return 0; }<br />
Im Beispiel ist Zaehlvariable zaehler und<br />
Funktion f jeweils nur für<br />
Übersetzungseinheit wechsel.c bzw.<br />
reset.c gültig.<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 60 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Komplettes Makefile für schalter /1<br />
1,2 Definition Compiler und Optionen<br />
3,4 Definition Programme und Quellen<br />
7 all per Konvention erstes Ziel, soll<br />
“alles” machen<br />
9 Es wird die Datei make.depend<br />
eingelesen und als Teil des Makefiles<br />
interpretiert<br />
1-15 : Wie wird schalter erstellt<br />
17 Die Datei make.depend wird nicht<br />
selbst erstellt, der Gnu-C Compiler<br />
kann das auf Basis der Quellen<br />
machen. Das erste Mal eine leere<br />
Datei erstellen ($ touch<br />
make.depend), damit es los geht.<br />
Ansonsten bei Strukturänderungen<br />
#include im Quellcode.<br />
1 CC=gcc<br />
2 CFLAGS= -Wall -g -ansi<br />
3 PROGS=schalter<br />
4 SRC=schalter.c reset.c wechsel.c \<br />
5 zustaende.c<br />
6<br />
7 all: $(PROGS)<br />
8<br />
10<br />
9 include make.depend<br />
11 schalter: schalter.o wechsel.o \<br />
12 reset.o zustaende.o<br />
13 $(CC) $(CFLAGS) schalter.o \<br />
14 wechsel.o reset.o zustaende.o \<br />
15 -o schalter<br />
16<br />
17 depend:<br />
18 $(CC) -MM $(SRC) > make.depend<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 61 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Komplettes Makefile für schalter /2<br />
Fortsetzung Makefile<br />
1,2 Ein beliebtes Ziel ist test zur<br />
Test-Automatisierung, ein anderes<br />
übliches Ziel wäre run<br />
4 clean ist keine Datei und muss daher<br />
immer “erstellt” werden<br />
6 clean räumt Projekt auf. Alle<br />
generierten Dateien werden gelöscht.<br />
9 Endungen von zu verarbeitenden<br />
Dateien sind .o, .c und .h<br />
11 Generische Regel: Um eine .o Datei<br />
aus einer .c Datei mit gleichem<br />
Namen zu machen . . .<br />
12 $< für erste Abhängigkeit (.c-Datei),<br />
$@ für Ziel (die .o-Datei)<br />
1 test: $(PROGS)<br />
2 ./schalter<br />
3<br />
4 .PHONY: clean<br />
5<br />
6 clean:<br />
7 -/bin/rm *.o $(PROGS)<br />
8<br />
10<br />
9 .SUFFIXES: .o .c .h<br />
11 %.o : %.c<br />
12 $(CC) -c $(CFLAGS) $< -o $@<br />
13 %.o : %.c %.h<br />
14 $(CC) -c $(CFLAGS) $< -o $@<br />
13 Wenn auch von .h Datei abhängig<br />
Weitere Abhängigkeiten nicht generisch,<br />
make.depend<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 62 / 326
<strong>Programmieren</strong> in C<br />
Getrennte Übersetzung<br />
Nutzen des Makefiles<br />
$ make -f clean<br />
/bin/rm *.o schalter<br />
$ make depend<br />
gcc -MM schalter.c reset.c wechsel.c zustaende.c > make.depend<br />
$ cat make.depend<br />
schalter.o: schalter.c reset.h zustaende.h wechsel.h<br />
reset.o: reset.c reset.h zustaende.h<br />
wechsel.o: wechsel.c wechsel.h zustaende.h<br />
zustaende.o: zustaende.c zustaende.h<br />
$ make<br />
gcc -c schalter.c -o schalter.o<br />
gcc -c wechsel.c -o wechsel.o<br />
gcc -c reset.c -o reset.o<br />
gcc -c zustaende.c -o zustaende.o<br />
gcc schalter.o wechsel.o \<br />
reset.o zustaende.o -o schalter<br />
$ make test<br />
./schalter<br />
0<br />
1 Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 63 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeiger<br />
Arbeitsspeicher<br />
• . . . ist in Speicherzellen eingeteilt<br />
• . . . ist Byte-weise adressierbar<br />
• . . . ist Wort-weise strukturiert<br />
0x0A0<br />
0x0A4<br />
42<br />
*ptr<br />
• Adressraum meist 2 32 oder 2 64 Bytes<br />
Zeiger<br />
0x100<br />
0x0A0<br />
&val<br />
• Speicherzelle, die Adresse einer<br />
anderen Speicherzelle beinhaltet<br />
• Typisiert, Anfangsadresse eines Werts<br />
Notation Zugriff<br />
• * ptr: Wert auf den der Zeiger ptr<br />
verweist, Inhaltsoperator *<br />
• &val: Adresse von Wert val,<br />
Adressoperator &<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 64 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeiger – Definition und Verwendung<br />
Notation Typ-Definition<br />
• *: Definiert einen Zeiger<br />
name auf <br />
• Beispiel: int *ptr;<br />
ptr ist Zeiger auf int<br />
Beispiel:<br />
• Variable val ist an Speicher mit<br />
Adresse (Hex) 0x0A0 abgelegt<br />
• Variable ptr ist an Speicher mit<br />
Adresse (Hex) 0x100 abgelegt<br />
• 32-Bit Wörter<br />
Ausgabe<br />
42 42 0x0A0 0x0A0<br />
0x100<br />
0x0A0<br />
0x0A4<br />
0x100<br />
1 int val = 42;<br />
2 int *ptr = &val;<br />
3<br />
42<br />
0x0A0<br />
4 printf("%d %d %p %p\n",<br />
5 val, *ptr,<br />
6 (void *) &val,<br />
7 (void *) ptr);<br />
*ptr<br />
8 printf("%p\n", (void *) &ptr);<br />
&val<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 65 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeigergröße<br />
Zeigergröße<br />
• Zeigergröße selbst durch Maschine<br />
festgelegt<br />
• Zeigergröße meist 4-Byte (32-Bit) oder<br />
8 Byte (64 Bit)<br />
• Zeigergröße unabhängig von<br />
Werte-Typ<br />
Beispiel<br />
0x0A0<br />
0x0A4<br />
0x100<br />
0x104<br />
0x108<br />
42<br />
'A' 'B'<br />
0x0A0<br />
0x0A4<br />
0x0A5<br />
• Ein int und zwei char<br />
• Auf 32-Bit Maschinen ist ein int 4 Byte<br />
groß und ein char 1 Byte<br />
• Zeiger sind auf 32-Bit Maschinen 4<br />
Byte groß, unabhängig vom Basis-Typ<br />
42 A B<br />
0x0A0 0x0A4 0x0A5<br />
0x100 0x104 0x108<br />
1 int a = 42; char b = ’A’, c = ’B’;<br />
2 int *ap = &a; char *bp = &b, *cp = &c;<br />
3<br />
4 printf("%d %c %c\n", a, b, c);<br />
5 printf("%p %p %p\n",<br />
6 (void *) &a, (void *) &b, (void *) &c);<br />
7 printf("%p %p %p\n",<br />
8 (void *) &ap,(void *) &bp, (void *) &cp);<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 66 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeiger auf Zeichen, Zeichenketten<br />
Zeiger auf Zeichen<br />
• Zeichen (Byte) ist kleinste<br />
adressierbare Einheit (Speicherzelle)<br />
Zeichenketten<br />
• Name des Felds kann als konstanter<br />
Zeiger auf das erste Element<br />
verwendet werden<br />
• Dereferenzierung entspricht<br />
Feldzugriff an Stelle 0<br />
• Achtung: Ein Zeichen ist ein<br />
Ganzzahltyp<br />
Beispielausgabe<br />
A 65 0x0A3<br />
B B 0x0A4 0x0A4<br />
0x0A0<br />
0x0A4<br />
0x100<br />
1 char ch = ’A’;<br />
'A'<br />
'B' 'C' 'D' '\0'<br />
0x0A3<br />
0x0A4<br />
2 char *chptr = &ch;<br />
3 char str[4] = "BCD";<br />
4 printf("%c %d %p\n",<br />
5 ch, ch, (void *) chptr);<br />
6 chptr = str;<br />
7 printf("%c %c %p %p\n",<br />
8 str[0], *chptr,<br />
9 (void *) chptr, (void *) &str[0]);<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 67 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeigerdefinition – Besonderheiten<br />
Syntax: *<br />
• Erst Typname <br />
• Dann Stern *<br />
• Schließlich Variablenname <br />
Beispiel: int *var<br />
Achtung<br />
• Der * bezieht sich auf den<br />
Variablennamen<br />
• Potentielles Problem bei mehreren<br />
Variablen in einer Definition<br />
• Der Typ eines Zeigers ist *<br />
Notationskonvention<br />
• * immer nahe am Variablennamen<br />
• Nie nahe am Typnamen<br />
1 int* ptr, qtr;<br />
1 /* entspricht */<br />
2 int *ptr;<br />
3 int qtr;<br />
1 int *ptr, *qtr;<br />
1 /* entspricht */<br />
2 int *ptr;<br />
3 int *qtr;<br />
int* ptr;<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 68 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Vorrangregeln von Operatoren<br />
Von hoch nach niedrig:<br />
10 () [] -> .<br />
Vorrang<br />
9 ! ˜ ++ -- + - * & (typ) sizeof<br />
8 * / %<br />
+ -<br />
7 ><br />
6 < >=<br />
== !=<br />
5 &<br />
ˆ<br />
|<br />
4 &&<br />
||<br />
3 ?:<br />
2 = += -= *= %= ˆ= &= =<br />
1 ,<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 69 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeiger – Beispiele/1<br />
1 unsigned long l0 = 0;<br />
2 unsigned long l1 = 1;<br />
3 unsigned long l2 = 2;<br />
4 unsigned long *pl[3] = {<br />
5 &l0, &l1, &l2 /* not ANSI-C, but C99 */<br />
6 };<br />
7 *pl[0] = 0;<br />
1 double d[3] = {1.0, 2.0, 3.0};<br />
2 double (*pd)[3] = &d;<br />
3 (*pd)[0] = 3.0;<br />
0 1 2<br />
pl 0x.. 0x.. 0x..<br />
l0 0 l1 1 l2 2<br />
0 1 2<br />
pd 0x.. d 1.0 2.0 3.0<br />
u 42<br />
1 unsigned int u=42;<br />
2 unsigned int *pu = &u;<br />
3 unsigned int **ppu = &pu;<br />
4 unsigned int ***pppu = &ppu;<br />
pppu<br />
ppu<br />
0x..<br />
pu<br />
0x..<br />
0x..<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 70 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeiger – Beispiele/2<br />
1 char ch;<br />
2 char *pc= &ch;<br />
3 char **ppc=&pc;<br />
4 char **xf[3][2];<br />
5 char **(*px)[3][2] = &xf;<br />
6<br />
7 ch = ’a’;<br />
8 *pc = ’a’;<br />
9 **ppc = ’a’;<br />
0 printf("%p %p\n",<br />
1 (void *) pc, (void *) ppc);<br />
2 xf[0][1] = ppc;<br />
3 **(*px)[0][1] = ’b’;<br />
4 printf("%c\n", ch);<br />
ppc<br />
px<br />
0x..<br />
0x..<br />
pc 0x.. ch<br />
xf 0<br />
1<br />
2<br />
0 1<br />
0x.. 0x..<br />
0x.. 0x..<br />
0x.. 0x..<br />
'a'<br />
'b'<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 71 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeigeroperationen, Zeiger auf void<br />
Operationen gleich(==), ungleich (!=)<br />
• Immer erlaubt<br />
• Test ob gleiche/ungleiche Adresse<br />
Zuweisung<br />
• Immer erlaubt<br />
• Gleicher Typ, sonst Warnung,<br />
vermeiden mit explizitem Cast<br />
• Von zu void * ohne Warnung<br />
void *, Zeiger auf beliebige Werte<br />
• Automatische Umwandlung bei<br />
Zuweisung<br />
• Dereferenzierung mit Inhaltsoperator<br />
verboten (was sollte rauskommen?)<br />
• Achtung: Böse, möglichst vermeiden<br />
1 char s[] = "hallo";<br />
2 char *cp = s;<br />
3 void *vp = cp;<br />
4 int *ip;<br />
5<br />
6 printf((s == cp) ? "==\n" : "!=\n");<br />
7 printf((s != cp) ? "!=\n" : "==\n");<br />
8<br />
9 ip = vp; /* keine Warnung */<br />
10 ip = cp; /* Warnung */<br />
11 ip = (int *) cp; /* keine Warnung */<br />
12<br />
13 printf("%i\n",<br />
14 *ip); /* was auch immer... */<br />
==<br />
==<br />
1819042152<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 72 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Zeigerarithmetik<br />
Zeiger und Zahlen<br />
• Addition und Subtraktion erlaubt<br />
• Ergebnis ist ein Zeiger<br />
• Effekt: Zeiger um Vielfaches des<br />
Platzbedarfs des Grundtyps ändern<br />
• typ *ptr; int i;<br />
int N = sizeof(typ);<br />
• ptr=ptr+i, ptr um i*N Byte erhöhen<br />
• ptr=ptr-i, um i*N Byte vermindern<br />
• ptr++, ptr--, ptr+=i . . . erlaubt<br />
Zeiger und Zeiger<br />
• Nur Subtraktion erlaubt<br />
• Ergebnis ist ganze Zahl<br />
Keine Zeigerarithmentik mit void *<br />
p p+1<br />
N Byte<br />
1 int ai[10];<br />
2 int *pi = &ai[0];<br />
3 double ad[10];<br />
4 double *pd = &ad[0];<br />
5 printf("%p %p %ld\n",<br />
6 (void *) pi, (void *) (pi+1),<br />
7 ((char *) (pi+1)) - ((char *) pi));<br />
8 printf("%p %p %ld\n",<br />
9 (void *) pd, (void *) (pd+1),<br />
10 ((char *) (pd+1)) - ((char *) pd));<br />
0x585e6210 0x585e6214 4<br />
0x585e61c0 0x585e61c8 8<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 73 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Beipiel – Zeichenketten<br />
Zeichenkette s mit Platz am Ende<br />
• Feld kann Zeiger zugewiesen werden<br />
Erste while-Schleife, Zeile 7<br />
• * ptr testet ob das Zeichen 0 ist<br />
• Läuft bis String-Ende<br />
Zweite while-Schleife, Zeile 9<br />
• Typische C-Idiom<br />
• Zuweisung, Zeigererhöhung und Test<br />
in einer Zeile<br />
• Doppelte Klammer vermeidet<br />
Warnung<br />
Gesamt<br />
• while-Schleifen – strcat(str, ttr)<br />
• for-Schleife – strlen(str)<br />
H a l l o u n d s o . \0<br />
1 char s[100] = "Hallo";<br />
2 char *p = s;<br />
3 char t[] = " und so.";<br />
4 char *q = t;<br />
5 int i;<br />
6<br />
7 while (*p)<br />
8 p++;<br />
9 while ((*p++ = *q++))<br />
10 ; /* leere Anweisung */<br />
11 p = s;<br />
12 for (i=0; *p++; i++)<br />
13 ; /* leere Anweisung */<br />
14 printf("%s (%d)\n", s, i);<br />
Hallo und so. (13)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 74 / 326
<strong>Programmieren</strong> in C<br />
Zeiger<br />
Rechnen mit Zeigern<br />
Zeigerarithmetik, gleicher Zeigertyp<br />
• Nur bei gleichen Zeigertypen sinnvoll<br />
• Beispiele<br />
cq - cp == 5<br />
cq == cp + 5<br />
cp == cq - 5<br />
Zeigerarithmetik bei verschiedenen<br />
Zeigertypen ist Unsinn<br />
• cq - ip ???<br />
• Keine Vermischung von Typen, was<br />
bedeutet +1?<br />
1 char cp[] = "abcdefghij";<br />
2 char *cq = cp+5;<br />
3 short int sp[] = {0,1,2,3,4};<br />
4 short int *sq = sp+2;<br />
5 int ip[] = {0, 1, 2};<br />
6 int *iq = ip + 1;<br />
7 double dp[] = { 3.1415, 2.7182 };<br />
8 double *dq = dp+1;<br />
cp<br />
cq<br />
a b c d e f g h i j<br />
sp<br />
sq<br />
0 1 2 3 4<br />
ip<br />
iq<br />
0<br />
1<br />
2<br />
dp<br />
dq<br />
3,1415<br />
2,<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 75 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeiger und Felder<br />
1 int af[] = {2,3,5,7,11,13,17,19,23,29};<br />
Feldnamen als Zeiger<br />
2 int i=6;<br />
• Der Name eines Feldes kann als<br />
3<br />
konstanter Zeiger auf das erste<br />
4 printf("%d == %d\n", af[i], *(af+i));<br />
Element des Feldes verwendet werden 5 printf("%d == %d\n", af[i], i[af]);<br />
Feldzugriff und Inhaltsoperation Zeiger<br />
• Es gilt ptr[i] == *((ptr) + (i))<br />
• Feldzugriff wird als Inhaltsoperation<br />
interpretiert<br />
• Äquivalenz gilt immer<br />
• Zeile 6: i[af] – so nicht<br />
programmieren<br />
Beispiel<br />
• Was macht nebenstehendes<br />
Programm?<br />
• 345 A 5<br />
17 == 17<br />
17 == 17<br />
1 char vstr[] = "12345";<br />
2 char *ptr = vstr;<br />
3<br />
4 printf ("%s %c %c", ptr+2,<br />
5 ’A’+ptr[5],<br />
6 3[ptr+1]);<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 76 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeiger und Felder sind nicht dasselbe/1<br />
Einem Feldnamen kann kein Zeiger<br />
zugewiesen werden<br />
• Der Feldname selbst ist kein Zeiger<br />
• Es wird kein Platz angelegt für den<br />
Feldnamen<br />
Ein Zeiger selbst braucht Speicherplatz<br />
• Der Zeiger beinhaltet die Adresse an<br />
der das erste Element des Feldes<br />
beginnt<br />
• Ein Zeiger zeigt bei Wertänderung auf<br />
andere Speicherbereiche<br />
1 char str[] = "abcde";<br />
2 char *ptr = "abcde";<br />
3<br />
4 ptr = str; /* geht */<br />
5 /* str = ptr; geht nicht */<br />
str a b c d e \0<br />
ptr 0x.. a b c d e \0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 77 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeiger und Felder sind nicht dasselbe/2<br />
Feld von Felder<br />
• Ein Feld von Feldern ist eigentlich ein<br />
grosses Feld<br />
• Row Major, zeilenweise<br />
• Die Größe ist fix<br />
1 char *pp[] =<br />
2 {"ein", "kleiner", "text"};<br />
3 char vv[][10] =<br />
4 {"ein", "kleiner", "text"};<br />
5 printf("%ld %ld\n", sizeof pp, sizeof vv)<br />
Feld von Zeiger<br />
12 30<br />
• Ein Feld von Zeigern ist ein normales<br />
eindimensionales Feld<br />
• Die Werte sind Zeiger auf Werte, bzw.<br />
Zeiger auf den Anfang von Feldern<br />
0<br />
1<br />
2<br />
pp<br />
0x..<br />
0x..<br />
0x..<br />
e i n \0<br />
k l e i<br />
t e s t<br />
n e r \0<br />
\0<br />
0<br />
1<br />
2<br />
vv<br />
e i n \0<br />
k l e i n e r \0<br />
t e s t \0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 78 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeigersalat<br />
1 char *c[] = { "ENTER", "NEW", "POINT",<br />
2 "FIRST" };<br />
3 char **cp[] = { c+3, c+2, c+1, c };<br />
4 char ***cpp = cp;<br />
5 printf("%s", **++cpp);<br />
6 printf("%s", *--*++cpp+3);<br />
7 printf("%s", *cpp[-2]+3);<br />
8 printf("%s\n", cpp[-1][-1]+1);<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
c<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
T \0<br />
T \0<br />
R \0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 79 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeigersalat – Zeile 5<br />
1 char *c[] = { "ENTER", "NEW", "POINT",<br />
2 "FIRST" };<br />
3 char **cp[] = { c+3, c+2, c+1, c };<br />
4 char ***cpp = cp;<br />
5 printf("%s", **++cpp);<br />
6 printf("%s", *--*++cpp+3);<br />
7 printf("%s", *cpp[-2]+3);<br />
8 printf("%s\n", cpp[-1][-1]+1);<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
c<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
T \0<br />
T \0<br />
R \0<br />
POINT<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 80 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeigersalat – Zeile 6<br />
1 char *c[] = { "ENTER", "NEW", "POINT",<br />
2 "FIRST" };<br />
3 char **cp[] = { c+3, c+2, c+1, c };<br />
4 char ***cpp = cp;<br />
5 printf("%s", **++cpp);<br />
6 printf("%s", *--*++cpp+3);<br />
7 printf("%s", *cpp[-2]+3);<br />
8 printf("%s\n", cpp[-1][-1]+1);<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
c<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
T \0<br />
T \0<br />
R \0<br />
POINTER<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 81 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeigersalat – Zeile 7<br />
1 char *c[] = { "ENTER", "NEW", "POINT",<br />
2 "FIRST" };<br />
3 char **cp[] = { c+3, c+2, c+1, c };<br />
4 char ***cpp = cp;<br />
5 printf("%s", **++cpp);<br />
6 printf("%s", *--*++cpp+3);<br />
7 printf("%s", *cpp[-2]+3);<br />
8 printf("%s\n", cpp[-1][-1]+1);<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
c<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
T \0<br />
T \0<br />
R \0<br />
POINTERST<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 82 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Zeigersalat – Zeile 8<br />
1 char *c[] = { "ENTER", "NEW", "POINT",<br />
2 "FIRST" };<br />
3 char **cp[] = { c+3, c+2, c+1, c };<br />
4 char ***cpp = cp;<br />
5 printf("%s", **++cpp);<br />
6 printf("%s", *--*++cpp+3);<br />
7 printf("%s", *cpp[-2]+3);<br />
8 printf("%s\n", cpp[-1][-1]+1);<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
c<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
T \0<br />
T \0<br />
R \0<br />
POINTERSTEW<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 83 / 326
<strong>Programmieren</strong> in C<br />
Zeiger und Felder<br />
Kommandozeilenparameter<br />
Parameter von main<br />
• Anzahl der Argumente (inklusive<br />
Name des Programms)<br />
int argc<br />
• Argumente als Feld von char-Zeigern<br />
char *argv[]<br />
Ähnlich wie in Java<br />
• Eigentlich umgekehrt<br />
args.c<br />
1 #include <br />
2<br />
3 int main(int argc, char *argv[]) {<br />
4 int i;<br />
5 for (i=0; i < argc; i++) {<br />
6 printf("%2d: %s\n", i, argv[i]);<br />
7 }<br />
8 return 0;<br />
9 }<br />
$ gcc args.c -o args<br />
$ args hallo tolle C Welt<br />
0: args<br />
1: hallo<br />
2: tolle<br />
3: C<br />
4: Welt<br />
0<br />
1<br />
2<br />
3<br />
4<br />
argv<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
a r g s \0<br />
h a l l<br />
t o I l<br />
C \0<br />
W e l t \0<br />
o \0<br />
e \0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 84 / 326
<strong>Programmieren</strong> in C<br />
Funktionsparameter<br />
Funktionsparameter<br />
Grundtypen<br />
• In Java Werte<br />
Änderbare Parameter durch<br />
Verpacken in Objekte<br />
• In C Werte<br />
Änderbare Parameter durch<br />
Adressoperator (“call by reference”)<br />
• Idiom für z.B. scanf<br />
Felder<br />
• In Java als Referenz übergeben<br />
Werte in Feld ändern möglich<br />
Zuweisung heißt Referenz kopieren<br />
• In C Parameter als Zeiger übergeben<br />
Werte in Feld können geändert<br />
werden<br />
Zuweisung an Feld nicht möglich<br />
1 void f1(int *pi) { *pi = 17; }<br />
2 void g1(int a[]) {<br />
3 int c[3] = {1,2,3};<br />
4 a = c; /* erlaubt */ }<br />
5 void g2(int *a) {<br />
6 int c[3] = {1,2,3}; a = c; }<br />
7 void g3(int *a) { a[0] = 17; }<br />
1 int i=2;<br />
2 int a[3] = {2,3,5};<br />
3 int b[3] = {2,3,5};<br />
4 /* b = a; nicht erlaubt */<br />
5 f1(&i);<br />
6 /* i == 17 */<br />
7 g3(a);<br />
8 /* a[0] == 17 */<br />
9 scanf("%d", &i);<br />
10 /* i == */<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 85 / 326
<strong>Programmieren</strong> in C<br />
Strukturen<br />
Strukturen – struct<br />
Wie Java-Klasse ohne Methoden<br />
• Alle Komponenten public<br />
Definition mit struct<br />
• Variablendefinition bei<br />
struct-Deklaration möglich<br />
• Spätere Variablendefinition möglich,<br />
immer mit Schlüsselwort struct<br />
• Initialisierung in Reihenfolge der<br />
Deklaration möglich<br />
• Größe implementierungsabhängig<br />
Zugriff auf Komponenten mit .-Operator<br />
Zuweisung ist Kopie<br />
44<br />
• NICHT wie in Java<br />
1234 Susi Sinnlos<br />
4711 Willi Wahnsinn<br />
1 struct person {<br />
2 char name[40];<br />
3 unsigned int id;<br />
4 } susi;<br />
5<br />
6 struct person rudi;<br />
7 struct person willi = {<br />
8 "Willi Wahnsinn",<br />
9 4711<br />
10 };<br />
1 strcpy (susi.name, "Susi Sinnlos");<br />
2 susi.id = 1234;<br />
3 rudi = willi;<br />
4 willi.id = 123456;<br />
5 willi.name[0] = ’X’;<br />
6 printf("%6d %s\n", susi.id, susi.name);<br />
7 printf("%6d %s\n", rudi.id, rudi.name);<br />
8 printf("%ld\n", sizeof (struct person));<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 86 / 326
<strong>Programmieren</strong> in C<br />
Strukturen<br />
Strukturen – Speicherlayout<br />
Speicherlayout<br />
• Compiler entscheidet<br />
• Keine Annahmen treffen<br />
Beispiel<br />
• Findet heraus wo was liegt<br />
• Code nicht gut/portabel<br />
0<br />
4<br />
8<br />
12<br />
16<br />
a 0x44ac2d20<br />
b<br />
c d<br />
d<br />
e<br />
Füll-Bytes<br />
1 struct p1 {<br />
2 short a;<br />
3 int b;<br />
4 char c[3];<br />
5 char d[4];<br />
6 int e;<br />
7 };<br />
1 struct p1 p;<br />
2 char *base = (char *) &p;<br />
3 printf("== p:%p ==\n", base);<br />
4 printf("a:%2ld b:%2ld c:%2ld d:%2ld e:%2l<br />
5 ((char *) &p.a)-base, ((char *) &p.b)-ba<br />
6 ((char *) &p.c)-base, ((char *) &p.d)-ba<br />
7 ((char *) &p.e)-base);<br />
== p:0x44ac2d20 ==<br />
a: 0 b: 4 c: 8 d:11 e:16<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 87 / 326
<strong>Programmieren</strong> in C<br />
Strukturen<br />
Strukturen und Zeiger<br />
Zugriff mit -><br />
• pp->id ist Kurzform für (*pp).id<br />
• Erlaubt einfachen Zugriff auf<br />
Komponenten einer Struktur<br />
• Beispiel: 987654 Rudi Ratlos<br />
Bequem bei Zeigerketten<br />
• Beispiel: 0<br />
lp a b c<br />
0x.. 2 0x.. 1 0x.. 0 0x..<br />
1 void change(struct person *pp) {<br />
2 strcpy(pp->name, "Rudi Ratlos");<br />
3 pp->id = 987654;<br />
4 }<br />
1 struct person *pp = &rudi;<br />
2 change(pp);<br />
3 printf("%6d %s\n", pp->id, pp->name);<br />
1 struct node {<br />
2 int data;<br />
3 struct node *next;<br />
4 };<br />
1 struct node c = {0, NULL};<br />
2 struct node b = {1, &c};<br />
3 struct node a = {2, &b};<br />
4 struct node *lp = &a;<br />
5 printf("%d\n", lp->next->next->data);<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 88 / 326
<strong>Programmieren</strong> in C<br />
Typdefinition<br />
Typdefinitionen – typedef<br />
Typdefinition<br />
• Syntax: typedef <br />
• Danach Verwendung von <br />
statt möglich<br />
• Kein neuer Typ, nur ein weiterer<br />
Name für denselben Typ<br />
Vorteil<br />
• (Meist) Kürzer<br />
• Portabler, da Typdefinition nur an<br />
einer Stelle steht<br />
Beispiel<br />
• Keine neuen Typen nur neue Namen<br />
• struct knoten wäre auch ok<br />
• knoten und struct knoten ergeben<br />
kein Namensproblem<br />
1 typedef int ganzzahl;<br />
2 typedef enum {ROT, GELB, GRUEN} ampel;<br />
3 typedef struct _knoten *knotenzeiger;<br />
4 typedef struct _knoten {<br />
5 knotenzeiger next;<br />
6 int data;<br />
7 } knoten;<br />
8 typedef struct _node {<br />
9 struct _node *next;<br />
10 int data;<br />
11 } node;<br />
12 typedef node *nodeptr;<br />
1 knoten k1, k2;<br />
2 knotenzeiger kp = &k2;<br />
3 k1.next = kp;<br />
4 node n1, n2;<br />
5 nodeptr np = &n1;<br />
6 node *nq = &n2;<br />
7 np->next = nq;<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 89 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Freispeicherverwaltung<br />
Speicher anfordern<br />
• Es gibt kein new<br />
• Speicher mit malloc anfordern<br />
• Anzahl Bytes angeben<br />
• Adresse wird zurückgegeben<br />
• Freispeicher wird von Betriebsystem<br />
verwaltet<br />
Speicher freigeben<br />
• Es gibt keinen Garbage Collector<br />
• Speicher mit free freigeben<br />
• Adresse als Parameter angeben<br />
• Größe dem Betriebssystem bekannt<br />
• Danach Zugriff auf Speicher illegal<br />
• Achtung: Keine Compiler-Warnung<br />
• Achtung: (Nicht unbedingt gleich)<br />
Fehler zur Laufzeit<br />
1 int len=10, i;<br />
2 char *a = malloc(len*sizeof(char));<br />
3 for (i=0; i < len; i++) {<br />
4 a[i] = i;<br />
5 }<br />
6 free(a);<br />
7 a[0] = 17; /* illegal, Laufzeit */<br />
0x200<br />
a,0x100<br />
0 1 2 3<br />
4 5 6 7<br />
8 9<br />
0x200<br />
Freispeicher,<br />
Heap<br />
Stack<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 90 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Dynamische Speicherverwaltung<br />
Funktionen zur dynamischen Speicherverwaltung<br />
• void *malloc(size_t size)<br />
Reserviert einen size Byte großen Speicherblock<br />
• void *calloc(size_t nEle, size_t eleSize)<br />
Reserviert einen nEle * eleSize Byte großen Speicherblock und füllt ihn mit Nullen<br />
• void free(void *ptr)<br />
Gibt den vormals mit [mc]alloc allokierten Speicherbereich an der Adresse ptr an<br />
das System zurück<br />
Alles definiert in stdlib.h<br />
• size_t ist ein vorzeichenloser Ganzzahltyp<br />
Fehlerfall<br />
• Falls beim Allokieren kein Speicherblock mehr zur Verfügung steht wird NULL<br />
zurückgegeben<br />
• NULL ist ein Makro, Zeiger auf nicht definierten Wert, verwenden wie null in Java<br />
• NULL ist meist (nicht immer) so definiert: #define NULL ((void *) 0)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 91 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Keine Garbage-Collection<br />
Achtung Speicherlecks (leak)<br />
• Speicher wird nicht automatisch<br />
freigegeben<br />
• Jeder allokierte Block muss<br />
freigegeben werden<br />
$ leak<br />
Kein Speicher nach 80330 mallocs<br />
$ leak -f<br />
ok nach 100000 mallocs<br />
ok nach 200000 mallocs<br />
ok nach 300000 mallocs<br />
ok nach 400000 mallocs<br />
ok nach 500000 mallocs<br />
...<br />
ok nach 50000000 mallocs<br />
...<br />
1 #include <br />
2 #include <br />
3 #include <br />
4 int main(int argc, char *argv[]) {<br />
5 int len = 10000, *a, run=1, mallocs=0;<br />
6 while(run) {<br />
7 a = malloc(len*sizeof(int));<br />
8 if (a == NULL) {<br />
9 printf("Kein Speicher nach %d mallocs\n",<br />
10 mallocs);<br />
11 run = 0;<br />
12 }<br />
13 mallocs += 1;<br />
14 if (mallocs % 100000 == 0)<br />
15 printf ("ok nach %d mallocs\n", mallocs);<br />
16 if (argc > 1 &&<br />
17 strcmp(argv[1], "-f") == 0)<br />
18 free(a);<br />
19 } return 0; }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 92 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Speicherlecks erkennen<br />
Speicherlecks Beispiel<br />
• Beispiel ähnlich<br />
• Lecks ohne Option -f<br />
Speicherlecks erkennen mit valgrind<br />
• valgrind, memory checker<br />
• Instrumentieren von vorhandenem<br />
Code<br />
• Einfach vor Programmaufruf<br />
valgrind<br />
1 #include <br />
2 #include <br />
3 #include <br />
4<br />
5 int main(int argc, char *argv[]) {<br />
6 int len = 10000, run=1, mallocs=0, i;<br />
7 int *aptr;<br />
8 while(run && (mallocs < 1000)) {<br />
9 aptr = malloc(len*sizeof(int));<br />
10 for (i=0; i 1 &&<br />
14 strcmp(argv[1], "-f") == 0)<br />
15 free(aptr);<br />
16 }<br />
17 return 0;<br />
18 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 93 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
valgrind Beispiellauf<br />
$ valgrind ./leakval.exe<br />
==12615== Memcheck, a memory error detector<br />
==12615== HEAP SUMMARY:<br />
==12615== in use at exit: 40,000,000 bytes in 1,000 blocks<br />
==12615== total heap usage: 1,000 allocs, 0 frees, 40,000,000 bytes allocated<br />
==12615== LEAK SUMMARY:<br />
==12615== definitely lost: 40,000,000 bytes in 1,000 blocks<br />
==12615== indirectly lost: 0 bytes in 0 blocks<br />
==12615== possibly lost: 0 bytes in 0 blocks<br />
==12615== still reachable: 0 bytes in 0 blocks<br />
==12615== suppressed: 0 bytes in 0 blocks<br />
$ valgrind ./leakval.exe -f<br />
==12618== Memcheck, a memory error detector<br />
==12618== HEAP SUMMARY:<br />
==12618== in use at exit: 0 bytes in 0 blocks<br />
==12618== total heap usage: 1,000 allocs, 1,000 frees, 40,000,000 bytes allocated<br />
==12618== All heap blocks were freed -- no leaks are possible<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 94 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Verkettete Liste – Header<br />
Einfach verkettete Liste<br />
• Zeiger auf Nachfolger<br />
• Wert ist Feld mit 80 Zeichen<br />
• Merken des Zeigers auf das erste Feld<br />
zur Repräsentation der Liste<br />
Hilfsroutinen<br />
• Liste anzeigen, show_list:<br />
Durchlaufen und Zeichenkette<br />
9<br />
10<br />
} slist;<br />
typedef slist *slptr;<br />
11<br />
ausgeben<br />
12 void show_list(slptr l);<br />
• Listenelement am Anfang einfügen, 13 slptr insert(slptr list, const char *s);<br />
insert: String mit max 80 Zeichen wird14 void delete_list(slptr list);<br />
kopiert<br />
15 slptr copy_list_reverse(slptr first);<br />
• Liste löschen, delete_list: Erstes<br />
Element schrittweise löschen<br />
• Kopieren, copy_list_reverse: Kopie<br />
hat umgekehrte Reihenfolge<br />
1 #ifndef SLIST_H<br />
2 #define SLIST_H<br />
3<br />
4 #define SMAXLEN 80<br />
5<br />
16<br />
6 typedef struct _slist {<br />
7 struct _slist *next;<br />
8 char s[SMAXLEN];<br />
17 #endif<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 95 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Verkettete Liste – Implementierung/1<br />
1 void show_list(slptr lis) {<br />
2 for (; lis; lis = lis->next)<br />
3 printf("%s ", lis->s);<br />
4 printf("\n");<br />
5 }<br />
6<br />
7 static void scopy(char *dest, const char *src) {<br />
8 strncpy(dest, src, SMAXLEN);<br />
9 dest[SMAXLEN-1] = 0;<br />
0 }<br />
1<br />
2 slptr insert(slptr lis, const char *s) {<br />
3 slptr neu = malloc(sizeof(slist));<br />
4 if (neu == NULL)<br />
5 return NULL;<br />
6 scopy(neu->s, s);<br />
7 neu->next = lis;<br />
8 return neu;<br />
9 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 96 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Verkettete Liste – Implementierung/2<br />
1 void delete_list(slptr lis) {<br />
2 slptr next;<br />
3 while (lis) {<br />
4 next = lis->next;<br />
5 free(lis);<br />
6 lis = next;<br />
7 }<br />
8 }<br />
9<br />
0 slptr copy_list_reverse(slptr lis) {<br />
1 slptr nlis = NULL;<br />
2 while (lis) {<br />
3 nlis = insert(nlis, lis->s);<br />
4 lis = lis->next;<br />
5 }<br />
6 return nlis;<br />
7 }<br />
lis<br />
a<br />
c<br />
0x..<br />
0x..<br />
b<br />
b<br />
0x..<br />
0x..<br />
c<br />
nlis<br />
a<br />
0x..<br />
0x..<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 97 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Verkettete Liste – SelectionSort<br />
SelectionSort<br />
• Gibt neue sortierte Liste zurück<br />
• Sortieren durch Auswahl des größten Elements<br />
• Aufsteigend sortiert<br />
Anmerkungen<br />
• Auswahl des größten Elements, neue Liste von hinten aufgebaut, dass man das<br />
nächste (kleinere) immer vorne anfügen kann<br />
• Arbeiten auf Kopie, also zunächste Kopie erstellen, Reihenfolge egal (Zeile 4)<br />
• Kopfelement um Sonderfälle zu vermeiden, wird nie verschoben<br />
• Bestimme größtes Element (Zeile 10-14)<br />
• Hänge größtes Element aus und in neue Liste ein (Zeile 15-18)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 98 / 326
<strong>Programmieren</strong> in C<br />
Freispeicherverwaltung<br />
Verkettete Liste – SelectionSort, Implementierung<br />
1 slptr selection_sort(slptr lis) {<br />
2 if (lis == NULL) { return lis; }<br />
3 slptr cp_lis=copy_list_reverse(lis), start=NULL;<br />
4 slist _first; /* Kopfelement, es wird niemals damit verglichen */<br />
5 slptr first = &_first; first->next = cp_lis;<br />
6 while (first->next) {<br />
7 slptr befmax=first, lis=first, hlis;<br />
8 while (lis->next) { /* Finde Maximales */<br />
9 if (strcmp(lis->next->s, befmax->next->s) > 0) {<br />
0 befmax = lis;<br />
1 }<br />
2 lis = lis->next;<br />
3 }<br />
4 hlis = befmax->next->next; /* Max. an Anfang der neuen Liste */<br />
5 befmax->next->next = start;<br />
6 start = befmax->next;<br />
7 befmax->next = hlis;<br />
8 }<br />
9 return start;<br />
0 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 99 / 326
<strong>Programmieren</strong> in C<br />
Varianten/Unions<br />
Varianten/Unions<br />
Ziel – Wenig Speicherplatz<br />
• Nur eine von mehreren Varianten<br />
• Bei struct müsste für alle Platz<br />
vorgehalten werden<br />
Variante – union<br />
• Syntax wie struct, aber union<br />
• Alle Komponenten erhalten dieselbe<br />
Anfangsadresse im Speicher<br />
• Bei struct hintereinander<br />
• Nur eine Variante ist gültig<br />
• Nur diese sollte verwendet werden<br />
• Leider sind alle verwendbar mit dann<br />
meist sinnlosen Werten<br />
• Größe ist die Größe der größten<br />
Variante<br />
1 union zahl {<br />
2 int i;<br />
3 char c[12];<br />
4 double d;<br />
5 };<br />
1 union zahl z1;<br />
2 z1.i = 42;<br />
3 printf("%12d ", z1.i);<br />
4 strcpy(z1.c, "42");<br />
5 printf("%12s ", z1.c);<br />
6 printf("%12d ", z1.i);<br />
7 printf("%12g\n", z1.d);<br />
42 42 12852 4.85435e-270<br />
4 2 \0<br />
12852<br />
4.85435e-270<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 100 / 326
<strong>Programmieren</strong> in C<br />
Varianten/Unions<br />
Beispiel – Varianten von Personen/1<br />
Zwei Personentypen<br />
• Studierende, STUD<br />
• Professoren, PROF<br />
Abbildung mit struct und union<br />
• Ein struct mit Klassifikator was das<br />
für eine Variante ist<br />
• union aus structs mit den Varianten<br />
1 enum typ { STUD, PROF };<br />
2<br />
3 struct person {<br />
4 enum typ was;<br />
5 union {<br />
6 struct {<br />
7 int matnr;<br />
8 double notenschnitt;<br />
9 int semester;<br />
10 } studi;<br />
11 struct {<br />
12 int persnr;<br />
13 int seitjahr;<br />
14 } prof;<br />
15 } details;<br />
16 };<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 101 / 326
<strong>Programmieren</strong> in C<br />
Varianten/Unions<br />
Beispiel – Varianten von Personen/2<br />
Erstellung von zwei Personen<br />
• Eine Studierende Susi<br />
• Ein Professor Roland<br />
Ausgabe, nächste Seite<br />
1 struct person susi;<br />
2 struct person roland;<br />
3<br />
4 susi.was = STUD;<br />
5 susi.details.studi.matnr = 123456;<br />
6 susi.details.studi.notenschnitt = 1.6;<br />
7 susi.details.studi.semester = 3;<br />
8<br />
9 roland.was = PROF;<br />
10 roland.details.prof.persnr = 654321;<br />
11 roland.details.prof.seitjahr = 1418;<br />
12<br />
13<br />
14 show(&susi);<br />
15 show(&roland);<br />
123456 1.6 3<br />
654321 1418<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 102 / 326
<strong>Programmieren</strong> in C<br />
Varianten/Unions<br />
Beispiel – Varianten von Personen/3<br />
Ausgabe von Personen<br />
• Je nach Variante unterschiedlich<br />
1 void show(struct person *p) {<br />
2 switch (p->was) {<br />
3 case STUD:<br />
4 printf("%6d %4.2g %1d\n",<br />
5 p->details.studi.matnr,<br />
6 p->details.studi.notenschnitt,<br />
7 p->details.studi.semester);<br />
8 break;<br />
9 case PROF:<br />
10 printf("%6d %4d\n",<br />
11 p->details.prof.persnr,<br />
12 p->details.prof.seitjahr);<br />
13 break;<br />
14 }<br />
15 }<br />
123456 1.6 3<br />
654321 1418<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 103 / 326
<strong>Programmieren</strong> in C<br />
Bitfelder<br />
Bitfelder<br />
1 struct punkt {<br />
Ziel – Wenig Speicherplatz<br />
2 /* XY-Position: 0-1024 */<br />
• Mehrere Zahlen mit kleinem<br />
3 unsigned x:10;<br />
Zahlenbereich kompakt repräsentieren 4 unsigned y:10;<br />
Umsetzung – Bitfelder<br />
• Syntax wie struct<br />
• Komponenten<br />
unsigned : <br />
• Es werden Anzahl für Zahl<br />
reserviert<br />
• statt unsigned auch signed möglich<br />
Zugriff<br />
• Punkt-Notation<br />
• Compiler übernimmt Bit-Shifterei<br />
• Achtung: Aktuelles Speicherlayout<br />
implementierungsabhängig<br />
5 /* RGB-Anteile: 0-255 */<br />
6 unsigned r:8;<br />
7 unsigned g:8;<br />
8 unsigned b:8;<br />
9 };<br />
x y r g b<br />
6-8 Byte je Punkt<br />
statt 20 (int) oder 10-12, 16 (short)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 104 / 326
<strong>Programmieren</strong> in C<br />
Bitfelder<br />
Bitfelder – Verwendung<br />
x y r g b<br />
1 struct punkt weissediagonale[1024];<br />
2 int i;<br />
3 for (i=0; i < 1024; i++) {<br />
4 weissediagonale[i].x = i;<br />
5 weissediagonale[i].y = i;<br />
6 weissediagonale[i].r =<br />
7 weissediagonale[i].g =<br />
8 weissediagonale[i].b = 255;<br />
9 }<br />
0 printf("%ld\n", sizeof weissediagonale);<br />
8192, entspricht 8 Byte, Trennung an Wortgrenze<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 105 / 326
<strong>Programmieren</strong> in C<br />
Funktionszeiger<br />
Funktionszeiger<br />
Ziel – Parametrisiertes Verhalten<br />
• Keine Objektorientierung<br />
• Funktionalität zuordnen/kapseln<br />
können<br />
Umsetzung – Zeiger auf Funktion<br />
• Parametervereinbarung wie gewohnt<br />
• Statt Funktionsname den<br />
Namen des Funktionszeigers in<br />
Klammern mit einem Stern davor<br />
• (*)<br />
Aufruf<br />
• Inhaltsoperator<br />
• Geht auch direkt mit Namen,<br />
was sonst sollte gemeint sein<br />
1 char g1[] = "Hallo";<br />
2 char g2[] = "Hey Depp";<br />
3<br />
4 char *nett(void) { return g1; }<br />
5 char *boese(void) { return g2; }<br />
6<br />
7 typedef char *(*grusstyp)(void);<br />
1 char *(*gruss1)(void);<br />
2 grusstyp gruss2;<br />
3<br />
4 gruss1 = nett;<br />
5 printf("%s, wie geht es?\n", (*gruss1)())<br />
6 printf("%s, wie geht es?\n", gruss1());<br />
7 gruss2 = boese;<br />
8 printf("%s, wie geht es?\n", gruss2());<br />
Hallo, wie geht es?<br />
Hallo, wie geht es?<br />
Hey Depp, wie geht es?<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 106 / 326
<strong>Programmieren</strong> in C<br />
Funktionszeiger<br />
Funktionszeiger – Beispiel qsort<br />
Quicksort<br />
• Bibliotheksfunktion qsort<br />
• Funktioniert für Felder von<br />
beliebigem Datentyp<br />
• Vergleichsfunktion muss<br />
übergeben werden<br />
Vergleichsfunktion<br />
• Gibt int zurück<br />
< 0 wenn kleiner, > 0 wenn<br />
größer, = 0 wenn gleich<br />
• Parameter sind Zeiger auf zu<br />
vergleichende Werte<br />
2 5 3<br />
2 3 5<br />
5 3 2<br />
• void *, jeder Typ<br />
• const Wert wird nicht geändert<br />
1 void show(int a[], int len) {<br />
2 int i;<br />
3 for (i=0; i < 3; i++)<br />
4 printf("%d ", a[i]);<br />
5 printf("\n");<br />
6 }<br />
7 int kleiner(const void *e1, const void *e2) {<br />
8 return *((int *) e1) - *((int *) e2);<br />
9 }<br />
10 int groesser(const void *e1, const void *e2) {<br />
11 return *((int *) e2) - *((int *) e1);<br />
12 }<br />
1 int a[3] = { 2, 5, 3 };<br />
2 show(a,3);<br />
3 qsort(a, 3, sizeof (int), kleiner);<br />
4 show(a,3);<br />
5 qsort(a, 3, sizeof (int), groesser);<br />
6 show(a,3);<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 107 / 326
<strong>Programmieren</strong> in C<br />
Makros<br />
Makros – Präprozessor<br />
• #include: Dateien einfügen<br />
• #define: Ersetzen von Text<br />
• #ifdef, #ifndef, #if defined, #if !defined, #if, #else, #elif, #endif, . . .<br />
Bedingte Übersetzung<br />
• Beispiel: Include-Guards<br />
• Beispiel: /usr/include/stdio.h<br />
1 #ifdef __USE_GNU<br />
2<br />
3 #endif<br />
1 #if defined __GNUC__ || defined __USE_GNU<br />
2<br />
3 #endif<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 108 / 326
<strong>Programmieren</strong> in C<br />
Makros<br />
Makros – Ersetzen von Text<br />
Ersetzen von Text<br />
• #define <br />
3 int main(void) {<br />
• wird durch ersetzt<br />
4 int iPI=0;<br />
• Ersetzungen finden weder innerhalb 5 char *s = " PI ist cool";<br />
von Zeichenketten statt noch innerhalb 6 printf("%g\n", PI);<br />
von Bezeichnern<br />
7 return 0;<br />
Verwendung<br />
• Wird auch für Konstanten verwendet,<br />
vermeiden wegen fehlender<br />
Typprüfung<br />
• Sinnvoll zum Beispiel für<br />
Parametrisieren von Typen<br />
makros.c<br />
1 #include <br />
2 #define PI 3.1415<br />
8 }<br />
1 $ ./makros<br />
2 3.1415<br />
3 $ gcc -E makros.c | tail<br />
4 # 940 "/usr/include/stdio.h" 3 4<br />
5 # 2 "makrosa.c" 2<br />
6 int main(void) {<br />
7 int iPI=0;<br />
8 char *s = " PI ist cool";<br />
9 printf("%g\n", 3.1415);<br />
10 return 0;<br />
11 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 109 / 326
<strong>Programmieren</strong> in C<br />
Makros<br />
Makros – Parameter<br />
Makros mit Parametern<br />
• Syntax:<br />
#define (, ..., ) \<br />
<br />
• Kein Leerzeichen zwischen Namen<br />
und Klammer auf(<br />
• Verwenden der Parameternamen im<br />
<br />
Rein textuelle Ersetzung<br />
• Keine Typen, also keine<br />
Typüberprüfung<br />
• Achtung bei Ausdrücken, nur textuelle<br />
Ersetzung!<br />
• Im Beispiel geht etwas mit der<br />
Operatorpräzedenz schief<br />
1 #include <br />
2<br />
3 #define add1(i,j) i+j<br />
4 #define mul1(i,j) i*j<br />
1 int i=3, j=4;<br />
2 printf("%d\n", mul1(i, j)); /* 12 */<br />
3 printf("%d\n", add1(i, j)); /* 7 */<br />
4 printf("%d\n", mul1(i+1, j)); /* 7 */<br />
5 printf("%d\n", add1(i, j)*2); /* 11 */<br />
Zeile 4: Ergebnis 7 statt 16<br />
i+1*j<br />
Zeile 5: Ergebnis 11 statt 14<br />
i+j*2<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 110 / 326
<strong>Programmieren</strong> in C<br />
Makros<br />
Makros – Parameter, Klammern<br />
Klammerung der Parameter vermeidet<br />
manche Probleme<br />
Leider nicht alle<br />
1 #define add2(i,j) ((i) + (j))<br />
2 #define mul2(i,j) ((i) * (j))<br />
1 int i=3, j=4;<br />
2 printf("%d\n", mul2(i, j)); /* 12 */<br />
3 printf("%d\n", add2(i, j)); /* 7 */<br />
4 printf("%d\n", mul2(i+1, j)); /* 16 */<br />
5 printf("%d\n", add2(i, j)*2); /* 14 */<br />
6<br />
7 printf("%d\n", add2(++i, ++i)*2); /* 20 *<br />
Zeile 7: Ergebnis 20 statt 18 ???<br />
((++i) + (++i))*2<br />
Seiteneffekte, was soll rauskommen?<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 111 / 326
<strong>Programmieren</strong> in C<br />
Makros<br />
Makros – Parameter, Klammern, Seiteneffekte<br />
Makros können Mehrfachverwendung mit<br />
1 #define quad(i) ((i)*(i))<br />
unerwünschten Seiteneffekten kaschieren<br />
Nicht machen<br />
1 int i=3;<br />
inline-Funktionen im Header verwenden 2 printf("%d\n", quad(++i)); /* 25 */<br />
ab C99<br />
3 printf("%d\n", i); /* 5 */<br />
Zeile 2: Ergebnis 25 statt 16 ???<br />
((++i) * (++i))<br />
Niemand sieht und erwartet im Quellcode<br />
die doppelte Erhöhung von i.<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 112 / 326
<strong>Programmieren</strong> in C<br />
Konstanten<br />
Konstanten<br />
Konstanten<br />
• Syntax: const ...<br />
• Modifizierer des Typs<br />
• Compiler stellt sicher, dass der Wert<br />
nicht geändert werden kann<br />
Statt #define besser const verwenden<br />
• Typüberprüfung findet statt<br />
• Achtung: In Headern als extern<br />
deklarieren ohne Wert und Wert in<br />
einer Übersetzungseinheit definieren<br />
• Alternative: enum für Feldgrößen da<br />
const dort nicht erlaubt<br />
1 #include "constlib.h"<br />
2<br />
3 #define ANTWORT 42<br />
4 const int ANSWER=42;<br />
5<br />
6 #define AGROESSE 100;<br />
7 enum { ASIZE=100 };<br />
8 char s[ASIZE];<br />
constlib.h<br />
1 #ifndef CONSTLIB_H<br />
2 #define CONSTLIB_H<br />
3 extern const int THEANSWER;<br />
4 #endif<br />
constlib.c<br />
1 #include "constlib.h"<br />
2 const int THEANSWER=42;<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 113 / 326
<strong>Programmieren</strong> in C<br />
Konstanten<br />
Konstanten und Zeiger<br />
Konstanten und Zeiger<br />
• const char *<br />
(veränderbarer) Zeiger auf konstantes<br />
Zeichen<br />
• char *const<br />
Konstanter Zeiger auf (veränderbares)<br />
Zeichen<br />
• const char *const<br />
Konstanter Zeiger auf konstantes<br />
Zeichen<br />
1 char s[100];<br />
2<br />
3 const char *a = s;<br />
4 /* a[0] = ’x’; verboten */<br />
5 a = s+1; /* ok */<br />
6<br />
10<br />
7 char *const b = s;<br />
8 b[0] = ’x’; /* ok */<br />
9 /* b = s+1; verboten */<br />
11 const char *const c="Fixer String";<br />
12 /* c[0] = ’x’; verboten */<br />
13 /* c = s+1; verboten */<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 114 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard-Bibliothek – Übersicht<br />
Standard-Bibliothek – Auszug<br />
• assert.h: Zusicherungen<br />
• ctype.h: Klassifizierung und Konversion von Zeichen<br />
• math.h: Mathematische Funktionen<br />
• stdarg.h: Variable Parameterlisten<br />
• stdio.h: Ein-/Ausgabe<br />
• stdlib.h: Speicherverwaltung, Stringkonvertierung, Zufallszahlen, . . .<br />
• string.h: String-/Speicherbearbeitung<br />
• time.h: Datum und Uhrzeit<br />
• ....<br />
Teil von ANSI-C / ISO-C<br />
• Syntax und Verhalten definiert<br />
• Meist plattformunabhängig, Unterstützung für Plattformabhängigkeiten (wenn man<br />
will/muss kann man plattformunabhängigen Code schreiben)<br />
• Viele weitere Bibliotheken (außerhalb des Standards) verfügbar<br />
Dokumentation: man <br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 115 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard-Bibliothek – assert<br />
Zusicherungen<br />
• assert()<br />
• Makro in assert.h<br />
• Falls Bedingung nicht erfüllt ist, dann<br />
wird Programm mit entsprechender<br />
Meldung abgebrochen.<br />
Übersetzung<br />
• Kein Code für assert, wenn die<br />
Konstante NDEBUG definiert ist.<br />
• Programm läuft schneller<br />
• Makros können mit Compiler-Option<br />
gesetzt werden<br />
• -DNDEBUG<br />
• In Makefile verwendbar, CFLAGS<br />
1 #include <br />
2 #include <br />
3 int mydiv(int zaehler, int nenner) {<br />
4 assert (nenner != 0);<br />
5 return zaehler/nenner;<br />
6 }<br />
7 int main(void) {<br />
8 printf("%d\n", mydiv(17,2));<br />
9 printf("%d\n", mydiv(17,0));<br />
10 return 0; }<br />
$ gcc assert.c -o assert<br />
$ ./assert<br />
8<br />
assert.exe: assert.c:5: div:<br />
Assertion ‘nenner != 0’ failed.<br />
Aborted<br />
$ gcc -DNDEBUG assert.c -o assert<br />
8<br />
Floating point exception<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 116 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard-Bibliothek – Standard I/O<br />
Zeiger auf Ströme<br />
• stdin (Eingabe), stdout (Ausgabe), stderr (Fehler)<br />
High-Level – gepuffert<br />
• FILE * (Zeiger auf Strom)<br />
• printf, scanf; fprintf, fscanf (Dateien);<br />
sprintf, sscanf (Strings)<br />
• puts, putc, gets, getchar, getc, fputs, fgetc (s String,<br />
c Char)<br />
• fopen, fclose (Dateien); fread, fwrite (binär), . . .<br />
• man stdio<br />
Low-Level – ungepuffert<br />
• int (handle)<br />
• Nicht Teil des ISO-Standards, POSIX-Standard (Unix)<br />
• open, creat, close, unlink, read, write, lseek, . . .<br />
stdin stdout<br />
Programm<br />
stderr<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 117 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard I/O – Beispiel, Datei I/O /1<br />
Ziel<br />
• Datei einlesen, optional<br />
Dateiname als<br />
Kommandzeilenparameter,<br />
sonst stdin<br />
• Datei out.strip schreiben<br />
• Zeilenweise<br />
• Innerhalb einer Zeile keine<br />
Wiederholungen von<br />
Whitespaces<br />
Umsetzung<br />
• stdio, ctype<br />
• Kommaoperator vermeiden<br />
1 #include <br />
2 #include <br />
3<br />
4 const char *outfname = "out.strip";<br />
5<br />
6 int main(int argc, char *argv[]) {<br />
7 FILE *fpin = stdin;<br />
8 FILE *fpout = fopen(outfname, "w");<br />
9 int last_space = 0;<br />
10<br />
11 if (argc >= 2) {<br />
12 fpin = fopen(argv[1], "r");<br />
13 }<br />
14 if (!fpin || !fpout) {<br />
15 fprintf(stderr, "oopps\n");<br />
16 return -1;<br />
17 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 118 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard I/O – Beispiel, Datei I/O /2<br />
1 while (!feof(fpin)) {<br />
2 int c = fgetc(fpin);<br />
3 if (c == EOF)<br />
4 break;<br />
5 if (isspace(c)) {<br />
6 last_space=1;<br />
7 if (c == ’\n’)<br />
8 fputc(c, fpout), last_space = 0;<br />
9 } else {<br />
10 if (last_space) {<br />
11 fputc(’ ’, fpout); last_space = 0;<br />
12 }<br />
13 fputc(c, fpout);<br />
14 }<br />
15 }<br />
16 fclose(fpin); fclose(fpout);<br />
17 return 0;<br />
18 }<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 119 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Standard-Bibliothek – Speicherblöcke und Strings<br />
Speicherfunktionen, extra Parameter size<br />
• memchr: Puffer nach Zeichen durchsuchen<br />
• memcmp: Speicherblöcke vergleichen<br />
• memmove: Speicherblock verschieben<br />
• memset: Speicher füllen<br />
Stringfunktionen, nur Anfangsadresse (n max. Zeichen)<br />
• strcat, strncat: Zeichenkette anhängen<br />
• strchr: String nach Zeichen durchsuchen<br />
• strcmp, strncmp: String vergleichen<br />
• strcpy, strncpy: String kopieren<br />
• strdup: String kopieren, neuer Speicher<br />
• strlen: Länge eines Strings<br />
• strstr: Nach Teilstring suchen<br />
• . . .<br />
Speicherfunktionen<br />
0x..0x..0x..0x..0x..0x..<br />
Speicherblöcke beliebiger Länge,<br />
beliebige Struktur (void *)<br />
Stringfunktionen<br />
H A L L O \0<br />
Speicherblöcke beliebiger Länge,<br />
0-terminiert, aus Zeichen (char *)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 120 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Strings – Beispiel /1<br />
Ziel<br />
• Zeichenkette der<br />
Kommandozeile zu einem<br />
dynamisch allokierten String<br />
zusammenfügen<br />
Umsetzung<br />
• string-Funktionen<br />
• stdlib-Funktionen<br />
Bemerkung<br />
• Viele strlen-Aufrufe nicht<br />
effizient<br />
• Was ist die Komplexität? Wie<br />
geht es besser?<br />
1 #include <br />
2 #include <br />
3 #include <br />
4<br />
5 int main(int argc, char *argv[]) {<br />
6 int i;<br />
7 int len=1;<br />
8 char *s = malloc(sizeof(char));<br />
9 s[0] = 0;<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 121 / 326
<strong>Programmieren</strong> in C<br />
Standard-Bibliothek<br />
Strings – Beispiel /2<br />
Komplexität<br />
• Aufwendig wegen strlen<br />
• Viele Allokationen trotz Trick mit<br />
Verdopplung<br />
• Kopieren eines immer wieder<br />
wachsenden Teils<br />
Besser<br />
• Zweimal durchlaufen, einmal<br />
Speicher berechnen, dann<br />
allokieren und füllen<br />
• Linear<br />
1 for (i=1; i
<strong>Programmieren</strong> in Python<br />
Einführung<br />
Python<br />
Pseudocode that runs<br />
Was ist Python?<br />
• Objektorientierte <strong>Skript</strong>sprache (“Perl by a sane person”)<br />
• Einfach erlernbar (Einsteigersprache), interaktiv, Open Source<br />
• Um Größenordnung schnellere Entwicklung, auch für Prototypen geeignet<br />
• Plattformunabhängig, interpretiert, Bytecode (JIT mit pypy)<br />
Features<br />
• Dynamische Typisierung, Garbage Collection<br />
• Eingebaute Datenstrukturen (Listen, Tupel, Dictionaries, String, . . . )<br />
• Mächtige Ausdrucksweise und Werkzeuge (Verketten, abbilden, slicen)<br />
• Klassische Kontrollstrukturen (imperativ), Objektorientierung und funktionale<br />
Primitive<br />
• Unterstützung für große Projekte (Module, Ausnahmen, . . . )<br />
• Integration (C, C++, Java, XMLRPC, REST, SOAP, . . . )<br />
• Bibliotheken (Web, Email, reguläre Ausdrücke, XML, GUI, Threading, Unittesting,<br />
Bildbearbeitung, . . . )<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 123 / 326
<strong>Programmieren</strong> in Python<br />
Einführung<br />
Historie<br />
Background<br />
• Treibende Kraft: Guido van Rossum, BDFL<br />
• Name von “Monty Python Flying Circus”<br />
Historie<br />
90: Als <strong>Skript</strong>sprache für verteiltes BS konzipiert<br />
91: Erste Veröffentlichung<br />
94: comp.lang.python<br />
Heute<br />
Implementierungen:<br />
99: Jython, Java VM<br />
01: psyco, native Code<br />
06: IronPython, .Net<br />
07: PyPy, Python in Python, JIT<br />
10: Python on Android<br />
• Aktuell CPython 2.7/3.3, jython 2.7a, IronPython 2.7, PyPy 1.9 (2.7)<br />
• Aktive Entwicklergemeinde, sehr viele Bibliotheken, python.org<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 124 / 326
<strong>Programmieren</strong> in Python<br />
Einführung<br />
Verbreitung<br />
Plattform für Anwendungen<br />
• Hunderte <strong>Skript</strong>e in /usr/bin<br />
• Blender, Maya: 3D-Graphik<br />
• Mercurial: Versionsmanagement<br />
• Trac: Projekt/Software Management<br />
• Google App Engine, Django,<br />
Raspberry Pi<br />
Interner Einsatz<br />
• Google, NASA, Yahoo, ILM<br />
Entwickler<br />
• Sehr weit verbreitet<br />
• Die meist genutzte “general purpose”<br />
<strong>Skript</strong>sprache<br />
• Top Ten in TIOBE<br />
http://www.tiobe.com/index.php/content/<br />
paperinfo/tpci/index.html<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 125 / 326
<strong>Programmieren</strong> in Python<br />
Einführung<br />
Umgebung<br />
Interpreter und Tools<br />
• www.python.org/2.7.3<br />
• Integrierte Entwicklungsumgebung<br />
(IDLE), und interaktiver Interpreter<br />
Interaktive “Shell” in IDLE<br />
• Lernen der Sprache<br />
• Experimentieren mit der Bibliothek<br />
• Testen der eigenen Programme<br />
• Auswerten von allen Ausdrücken<br />
Alternativen: Emacs, eclipse pydev<br />
Online-Lektüren (neben Buch)<br />
• docs.python.org/2/tutorial/<br />
• wiki.python.org/moin/BeginnersGuide<br />
• pythonchallenge.com, checkio.org<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 126 / 326
<strong>Programmieren</strong> in Python<br />
Einführung<br />
IDLE Übersicht<br />
Interaktive Shell und Editoren<br />
• Im Editor mit F5 Programm in<br />
interaktiver Shell ausführen<br />
• Interaktive Shell ist kein Editor<br />
Integrierter Debugger<br />
• Stop, Over, Out<br />
• Mitlaufen Source<br />
• Anzeige Stack, lokale/globale<br />
Variablen<br />
• Seltener benötigt als in C<br />
• Interaktives Testen<br />
• Weniger Fehler in Python ;-)<br />
Alternativen<br />
• Emacs: solide, interaktiv<br />
• Eclipse pydev: mächtig, nicht interaktiv<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 127 / 326
<strong>Programmieren</strong> in Python<br />
Einführung<br />
Encoding bei Python <strong>Skript</strong>en – Unicode einstellen<br />
Angabe der Zeichenkodierung<br />
• Erste Zeile im <strong>Skript</strong><br />
# -*- coding: -*-<br />
oder zweite Zeile, falls erste<br />
#!/usr/bin/python<br />
• Spezieller Kommentar<br />
• Teilt python (und IDLE) das Encoding<br />
des Quelltexts mit<br />
Verfügbare Zeichenkodierungen<br />
• utf-8, empfohlen<br />
• Unicode: alle Sprachen<br />
• Ab Python 3.0 Standard<br />
• Sehr stark empfohlen<br />
• iso-8859-1, vermeiden<br />
1 #!/usr/bin/python<br />
2 # -*- coding: utf-8 -*-<br />
3<br />
4 print "Hello Python World"<br />
1 Shebang: Starte den<br />
Python-Interpreter mit dem folgenden<br />
Zeilen als interaktive Eingabe<br />
2 Encoding: Der ganze Quelltext,<br />
inklusive Kommentare und den Texten<br />
in Strings, ist in dem angegebenen<br />
Encoding<br />
Alle ausführbaren Programme<br />
mit Zeilen 1 und 2 beginnen<br />
• Standard Westeuropa, latin1<br />
• Böse: Mac-Roman, cp1285<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 128 / 326
<strong>Programmieren</strong> in Python<br />
Erste Schritte<br />
Erste Schritte – Zahlen und Ausdrücke<br />
1 >>> print "Hallo Python Welt"<br />
2 Hallo Python Welt<br />
3<br />
4 >>> # Kommentare<br />
5<br />
6<br />
7 >>> 2 # Integer-Zahlen<br />
8 2<br />
9<br />
0 >>> 3.14 # Fliesskommazahlen<br />
1 3.14<br />
2<br />
3 >>> "String" # Zeichenketten<br />
4 ’String’<br />
5<br />
6 >>> 0xff # Hex<br />
7 255<br />
8<br />
9 >>> 0377 # Oktal<br />
0 255<br />
1 >>> 6+2 # Ausdruecke<br />
2 8<br />
3<br />
4 >>> 6*2<br />
5 12<br />
6<br />
7 >>> 6/2<br />
8 3<br />
9<br />
10 >>> 6/5 # Vorgabe ganzzahlig (2.x)<br />
11 1<br />
12<br />
13 >>> 6//5 # Explizit ganzzahlig ([23].x)<br />
14 1<br />
15<br />
16 >>> 3**4 # Exponenten<br />
17 81<br />
18<br />
19 >>> 3+1j # Komplexe Zahlen<br />
20 (3+1j)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 129 / 326
<strong>Programmieren</strong> in Python<br />
Erste Schritte<br />
Erste Schritte – Zuweisungen und Tests<br />
1 >>> x = 1 # Variablenzuweisung<br />
2 >>> x # hat den zugewiesenen Wert<br />
3 1<br />
4<br />
5 >>> x = y = 2 # Mehrfachzuweisung<br />
6 >>> x<br />
7 2<br />
8 >>> y<br />
9 2<br />
0<br />
1 >>> abs(-3) # eingebaute Funktionen<br />
2 3<br />
3<br />
4 >>> 0 < 1 # Tests<br />
5 True<br />
6 >>> 1 < 0<br />
7 False<br />
1 >>> True == 1 # Bool neuer Typ<br />
2 True<br />
3 >>> False == 0<br />
4 True<br />
5<br />
6 >>> 0 < 5 < 10 # Mehrfachtest<br />
7 True<br />
8<br />
9 >>> True and False<br />
10 False<br />
11 >>> True or False<br />
12 True<br />
13<br />
14 >>> not "eins"<br />
15 False<br />
16 >>> not False<br />
17 True<br />
18<br />
19 >>> "eins" and "zwei" # letzter Wert<br />
20 ’zwei’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 130 / 326
<strong>Programmieren</strong> in Python<br />
Erste Schritte<br />
Erste Schritte – Binäres Rechnen und Division<br />
1 >>> x = 2 # binaer ...000010<br />
2<br />
3 >>> x >> x & 0xff # binaeres Und<br />
7 2<br />
8<br />
9 >>> x | 1 # binaeres Oder<br />
0 3<br />
1<br />
2 >>> ~x # Komplement<br />
3 -3<br />
4<br />
5 >>> x^3 # binaeres XOR<br />
6 1<br />
1 >>> 3/2 # ganzzahlige Division (2.x)<br />
2 1<br />
3 >>> 3//2 # ganzzahlige Division ([23].x)<br />
4 1<br />
5 >>> 3.0/2 # Hochkonvertieren<br />
6 1.5<br />
7 >>> 3.0//2 # Abschneiden<br />
8 1.0<br />
9 >>> 3./2 # 0 nicht notwendig<br />
10 1.5<br />
11 >>> 10 % 3 # Module, Rest<br />
12 1<br />
13 >>> 10 // 3 # ganzzahlig<br />
14 3<br />
15 >>> 3*(10//3) + (10%3)<br />
16 10<br />
17 >>> 10.0//3 # erzwungen ganzzahlig<br />
18 3.0 # anderer Typ<br />
19 >>> 10.0/3<br />
20 3.3333333333333335<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 131 / 326
<strong>Programmieren</strong> in Python<br />
Erste Schritte<br />
Große Zahlen und Konvertierung<br />
1 >>> 3e10 # Exponentenschreibweise<br />
2 30000000000.0<br />
3<br />
4 >>> 2**10 # Potenzieren<br />
5 1024<br />
6 >>> 2**20 # grosse ganze Zahl<br />
7 1048576<br />
8 >>> 2**1000 # sehr grosse ganze Zahl<br />
9 107150860718626732094842504906000181<br />
0 056140481170553360744375038837035105<br />
1 112493612249319837881569585812759467<br />
2 291755314682518714528569231404359845<br />
3 775746985748039345677748242309854210<br />
4 746050623711418779541821530464749835<br />
5 819412673987675591655439460770629145<br />
6 711964776865421676604298316526243868<br />
7 37205668069376L<br />
1 >>> 3L # explizit grosse Zahlen<br />
2 3L<br />
3 >>> float(3) # explizite Konvertierung<br />
4 3.0 # in double<br />
5 >>> int(3.0) # und zurueck<br />
6 3<br />
7 >>> long(3.0) # explizite Konvertierung<br />
8 3L<br />
9 >>> int("12") # auch fuer Strings<br />
10 12<br />
11 >>> int("11", 16) # explizite Basis<br />
12 17<br />
13<br />
14 >>> int("zwoelf") # nur wenn moeglich<br />
15 # ansonsten Ausnahme<br />
16 Traceback (most recent call last):<br />
17 File "", line 1, in <br />
18 ValueError: invalid literal for int()<br />
19 with base 10: ’zwoelf’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 132 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Zahlen<br />
Zahlen und Operationen<br />
Zahlentypen<br />
• ganze Zahlen, int und long (beliebig lang)<br />
• Gleitkommazahlen, float mit double Genauigkeit,<br />
komplexe Zahlen<br />
• Intuitive Darstellung und Eingabe<br />
Alle üblichen arithmetischen Operationen<br />
• Standardarithmetik: +, -, * , /, ** , %, //<br />
• Logische Arithmetik: ~, ^, |, &, <br />
• Vorrangregeln und Klammern wie gewohnt<br />
1 Python 2.7.3<br />
2 >>> 3/2<br />
3 1<br />
4 >>> 3//2<br />
5 1<br />
1 Python 3.2.3 ...<br />
2 >>> 3/2<br />
3 1.5<br />
4 >>> 3//2<br />
5 1<br />
Boolesche Werte: False, True<br />
• Entspricht 0 und 1 (Historie)<br />
1<br />
2<br />
>>> 0 or ""<br />
or "Hallo"<br />
• Oder leerer String, nichtleerer String, . . .<br />
3 or "Welt"<br />
Logische Ausdrücke: and, or, not<br />
• Erstes bestimmendes Element wird zurück gegeben<br />
• Die andere Argumente werden nicht ausgewertet<br />
4 ’Hallo’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 133 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Zahlen<br />
Ausdrücke<br />
Aufrufe von Funktionen und Methoden<br />
• Funktionsaufrufe<br />
• Methodenaufrufe<br />
• Interaktive Ausgabe des Wertes<br />
• Zusammengesetzte Ausdrücke<br />
• Bereichstests<br />
Werte ausgeben in der interaktiven<br />
Kommandozeile<br />
• Zuweisungen haben keinen Wert<br />
• Wert von Ausdrücken wird<br />
ausgegeben<br />
• print für explizite Ausgabe<br />
1 >>> lis = [3,1,2]<br />
2 >>> len(lis) # Funktionsaufruf<br />
3 3<br />
4 >>> lis.append(8) # Methode<br />
5 >>> lis # Ausgabe<br />
6 [3, 1, 2, 8]<br />
7 >>> len(lis) < 6 and len(lis)<br />
8 # Zusammengesetzt<br />
9 4<br />
10 >>> 1 < len(lis) < 8 # Bereich<br />
11 True<br />
1 >> lis<br />
2 [3, 1, 2]<br />
3 >>> print lis # 2.x<br />
4 [3, 1, 2]<br />
5 >>> print(lis) # 2.x, 3.x<br />
6 [3, 1, 2]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 134 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Zahlen<br />
Ausgabe mit print<br />
Ausgabe von Objekten mit print<br />
• Lesbare Ausgabe von Objekten<br />
• Ausgabe aller Objekte durch<br />
Leerzeichen getrennt<br />
• Mit Komma am Ende wird<br />
Zeilenumbruch unterdrückt<br />
• Ausgabe mit Formatstring, wie in C,<br />
%-Operator<br />
• Python 3.x, nur noch in Klammern<br />
(jetzt schon möglich)<br />
Alternative<br />
• Ausgabe wie in Java<br />
1 >>> lis = [1,2,3]<br />
2 >>> print lis, "zwei", 4<br />
3 [1, 2, 3] zwei 4<br />
4 >>> print lis,"zwei",4; print "weiter"<br />
5 [1, 2, 3] zwei 4<br />
6 weiter<br />
7 >>> print lis,"zwei",4,; print "weiter"<br />
8 [1, 2, 3] zwei 4 weiter<br />
9 >>> print "%s %s" % ("Hallo", "Welt")<br />
10 Hallo Welt<br />
11 >>> print(lis)<br />
12 [1, 2, 3]<br />
1 >>> import sys<br />
2 >>> sys.stdout.write("Hallo Welt\n")<br />
3 Hallo Welt<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 135 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Zeichenkette, Strings – Darstellung<br />
Syntax<br />
• Einfache oder doppelte<br />
Anführungszeichen<br />
• Nicht limitierendes Anführungszeichen<br />
nutzbar<br />
• Alternativ Escape-Zeichen verwenden<br />
Backslash \<br />
1 >>> "hallo"<br />
2 ’hallo’<br />
3 >>> ’hallo’<br />
4 ’hallo’<br />
1 >>> "spam’s"<br />
2 "spam’s"<br />
3 >>> ’spam"s’<br />
4 ’spam"s’<br />
5 >>> ’spam\’s’<br />
6 "spam’s"<br />
Mehrzeilige Strings<br />
• Drei Anführungszeichen am Anfang<br />
und am Ende<br />
• Zeilenendezeichen als \n verfügbar<br />
• Alle Anführungszeichen verwendbar<br />
1 >>> """hallo<br />
2 ... du "tolle"<br />
3 ... ’perfekte’ Welt """<br />
4 ’hallo\n du "tolle"\n<br />
\’perfekte\’ Welt ’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 136 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Strings – Operationen<br />
Alle üblichen Operationen vorhanden<br />
+ Konkatenation<br />
* Wiederholung<br />
[+i] Indizierung<br />
positive Zahl, 0 ist erstes Zeichen<br />
[-i] Indizierung von hinten<br />
negative Zahl, -1 ist letztes Zeichen<br />
• Slicing<br />
[von:bis] Ausschnitt von inklusive, bis exklusive<br />
[von:] Ausschnitt bis Ende<br />
[:bis] Ausschnitt ab Anfang<br />
[:] Gesamt (Kopie)<br />
1 >>> "Hallo" + " Welt"<br />
2 ’Hallo Welt’<br />
3 >>> "Hallo"*3<br />
4 ’HalloHalloHallo’<br />
5 >>> "Hallo"[0]<br />
6 ’H’<br />
7 >>> "Hallo"[-1]<br />
8 ’o’<br />
1 >>> "Hallo"[1:3]<br />
2 ’al’<br />
3 >>> "Hallo"[1:]<br />
4 ’allo’<br />
5 >>> "Hallo"[:-1]<br />
6 ’Hall’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 137 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Slicing<br />
"SLICEOFSPAM"[von:bis]<br />
• von, einschließend<br />
• bis, ausschließend<br />
Vorzeichen<br />
• Positive Zahlen, von links, ab 0<br />
• Negative Zahlen, von rechts, ab -1<br />
Dritter Parameter Schrittweite<br />
• "SLICEOFSPAM"[von:bis:step]<br />
• Schrittweite, normalerweise 1<br />
Geht auch mit Listen (später)<br />
0 1 2 3 4 5 6 7 8 9 10<br />
s l i c e o f s p a m<br />
-11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1<br />
1 >>> "sliceofspam"[2:-1]<br />
2 ’iceofspa’<br />
3 >>> "sliceofspam"[5:]<br />
4 ’ofspam’<br />
5 >>> "sliceofspam"[:5]<br />
6 ’slice’<br />
7 >>> "sliceofspam"[2:5]<br />
8 ’ice’<br />
1 >>> "sliceofspam"[2:-1:3]<br />
2 ’iop’<br />
3 >>> "sliceofspam"[::4]<br />
4 ’sep’<br />
5 >>> lis = [0,1,2,3,4,5,6,7]<br />
6 >>> lis[::2], lis[1::2]<br />
7 ([0, 2, 4, 6], [1, 3, 5, 7])<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 138 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Strings – Formatierung und Builtins<br />
Formatierung<br />
• Formatstring und Argumente<br />
• Ähnlich zu C, printf<br />
• %s String<br />
• %d Zahl<br />
• %x Hexadezimal<br />
• %e, %f, %g Gleitkommaformate<br />
• %% Prozentzeichen<br />
Benamtes Argument<br />
• %()<br />
• Durch bestimmter Wert in<br />
Abbildung als Argument<br />
• Gefolgt von Argumenttyp<br />
1 >>> "ein %s Papagei" % "toter"<br />
2 ’ein toter Papagei’<br />
3 >>> "%d %s Papageie" % (2, "tote")<br />
4 ’2 tote Papageie’<br />
5 >>> "%x" % 42<br />
6 ’2a’<br />
7 >>> "%X" % 42<br />
8 ’2A’<br />
9 >>> "%e %f %g" % (1.1, 1.2, 1.3)<br />
10 ’1.100000e+00 1.200000 1.3’<br />
11 >>> "%%%s%%" % "hallo"<br />
12 ’%hallo%’<br />
1 >>> "%(name)s heisst %(name)s" %<br />
2 {"name": "Eric"}<br />
3 ’Eric heisst Eric’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 139 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Strings – Builtins und raw Strings<br />
Eingebaute Funktionen, Builtins<br />
• Länge mit len<br />
• Standardoperationen für Vergleich<br />
• Test auf Enthaltensein mit in<br />
raw Strings<br />
• Steuerzeichen quotieren<br />
• Hilfreich bei regulären Ausdrücken,<br />
später<br />
1 >>> len("Hallo")<br />
2 5<br />
3 >>> "hallo" < "wallo"<br />
4 True<br />
5 >>> "al" in "Hallo"<br />
6 True<br />
1 >>> r"raw \n string"<br />
2 ’raw \\n string’<br />
3 >>> print r"raw \n string"<br />
4 raw \n string<br />
5 >>> "normaler \n string"<br />
6 ’normaler \n string’<br />
7 >>> print "normaler \n string"<br />
8 normaler<br />
9 string<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 140 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Strings – weitere Features<br />
string-Modul<br />
• als Modul “importieren”<br />
• Funktionen oder String-Methoden<br />
• Groß- und Kleinschreibung<br />
• Suchen, finden, ersetzen<br />
• Konvertieren, splitten, kleben<br />
• Konkatenation automatisch<br />
• Leerzeichen entfernen<br />
Kommandozeilenargumente<br />
• Modul sys<br />
• Liste von Argumente sys.argv<br />
$ python argv.py a b c d<br />
[’argv.py’, ’a’, ’b’, ’c’, ’d’]<br />
1 >>> import string<br />
2 >>> "ab".upper(), string.upper("ab")<br />
3 (’AB’, ’AB’)<br />
4 >>> string.find("spammify", "mm")<br />
5 3<br />
6 >>> string.atoi("42") # int("42") besser<br />
7 42<br />
8 >>> string.split("spammify"), "mm")<br />
9 [’spa’, ’ify’]<br />
10 >>> "XX".join(["spa", "ify"])<br />
11 ’spaXXify’<br />
12 >>> "spa" "XX" "ify"<br />
13 ’spaXXify’<br />
14 >>> string.strip(" Meaning of Life ")<br />
15 ’Meaning of Life’<br />
1 #!/usr/bin/python<br />
2 import sys<br />
3 print sys.argv<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 141 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Strings<br />
Eigenschaften von Strings<br />
Strings sind unveränderlich<br />
• Operation mit Strings (+, [], etc.)<br />
erzeugen immer neue Strings<br />
• Vorhandene Strings werden niemals<br />
verändert<br />
Strings sind Sequenzen<br />
• Geordnet, die Position der Elemente<br />
ist wichtig<br />
• Klare Menge von unterstützten<br />
Operationen<br />
• Sequenz von Zeichen<br />
Unicode Strings<br />
• u vor dem String<br />
• Typ unicode, nicht str<br />
1 >>> s = "hallo"<br />
2 >>> s[0] = "H"<br />
3 Traceback (most recent call last):<br />
4 File "", line 1, in <br />
5 TypeError: ’str’ object does not<br />
6 support item assignment<br />
1 >>> s = u"hallo"<br />
2 >>> s<br />
3 u’hallo’<br />
4 >>> s == "hallo"<br />
5 True<br />
6 >>> type("hallo"), type(u"hallo")<br />
7 (, )<br />
8 >>> u"hallo" == "hallo"<br />
9 True<br />
>>> "hällo" == u"hällo"<br />
__main__:1: UnicodeWarning: Unicode<br />
equal comparison failed...<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 142 / 326
<strong>Programmieren</strong> in Python<br />
Datentypen, Typhierarchie<br />
Typhierarchie eingebauter Typen<br />
object als Wurzel für alle Typen<br />
isinstance zum Testen<br />
1 >>> isinstance(3, int)<br />
2 True<br />
3 >>> isinstance(3, object)<br />
4 True<br />
object<br />
Ganze<br />
Zahlen<br />
Zahlen<br />
float<br />
Kollektionen<br />
Sequenzen Mengen Abbildungen<br />
unveränderlich veränderlich set dict<br />
int<br />
complex<br />
str<br />
list<br />
long<br />
fractions.<br />
Fraction<br />
unicode<br />
tuple<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 143 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen<br />
Kollektionen<br />
Eingebaute Kollektionen<br />
• Eingebaute Typen zum Verwalten von mehreren Objekten<br />
• Teil der Sprache, nicht nur der Bibliothek<br />
Vorteile<br />
• Effiziente Implementierung<br />
• Einfache Formulierung<br />
• Konzentration aufs Problem<br />
nicht auf technische<br />
Implementierungsdetails<br />
Umfangreich<br />
• Alles was man braucht<br />
• Ungefähr java.util.*<br />
• Strings, Listen, Tupel,<br />
Mengen, Wörterbücher<br />
object<br />
Kollektionen<br />
Sequenzen Mengen Abbildungen<br />
unveränderlich<br />
str<br />
unicode<br />
tuple<br />
veränderlich<br />
list<br />
set<br />
dict<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 144 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Tupel<br />
Tupel – Sequenz<br />
Tupel sind eine Sequenz<br />
• Syntax n-Tupel, n≥ 2 wie erwartet<br />
• 1-Tupel hat spezielle Syntax<br />
(1) wäre nur ein arithmetischer<br />
Ausdruck mit Klammerung<br />
• Leeres Tupel wie erwartet<br />
Beliebig kombinierbar<br />
• Beliebige Typen, schachtelbar<br />
Indizierung<br />
• mit []<br />
• Slicing (wie mit allen Sequenzen)<br />
Ergebnis ist wieder Tupel<br />
1 >>> (1, 2)<br />
2 (1, 2)<br />
3 >>> (1, 1, 1)<br />
4 (1, 1, 1)<br />
5 >>> (1, )<br />
6 (1,)<br />
7 >>> (1)<br />
8 1<br />
9 >>> ()<br />
10 ()<br />
11 >>> (1, "eins", 2.0, (34, 4))<br />
12 (1, ’eins’, 2.0, (34, 4))<br />
13 >>> tup = (1, "zwei", (3, 4))<br />
14 >>> tup[0]<br />
15 1<br />
16 >>> tup[2][1]<br />
17 4<br />
18 >>> tup[1:]<br />
19 (’zwei’, (3, 4))<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 145 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Tupel<br />
Tupel – Builtins<br />
Builtins von Sequenzen<br />
• Länge mit len<br />
• Konkatenation mit +<br />
• Wiederholung mit *<br />
• Test auf Enthaltensein mit in<br />
Automatisch Tupel<br />
• Auch ohne Klammern<br />
Tupelzuweisung<br />
• Nette Syntax<br />
• Geht auch ohne Klammern<br />
• Gut bei Rückgabewerten<br />
1 >>> tup = (1, "zwei", (3, 4))<br />
2 >>> len(tup)<br />
3 3<br />
4 >>> tup + tup<br />
5 (1, ’zwei’, (3, 4), 1, ’zwei’, (3, 4))<br />
6 >>> tup*2<br />
7 (1, ’zwei’, (3, 4), 1, ’zwei’, (3, 4))<br />
8 >>> (3, 4) in tup<br />
9 True<br />
1 >>> 1, 2<br />
2 (1, 2)<br />
3 >>> (1, 2)<br />
4 (1, 2)<br />
5 >>> (a, b) = (1, 2)<br />
6 >>> print a, b<br />
7 1 2<br />
8 >>> b, a = a, b<br />
9 >>> a, b<br />
10 (2, 1)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 146 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Tupel<br />
Tupel – Unveränderliche Sequenz<br />
Tupel sind unveränderlich<br />
• Operationen mit Tupel erzeugen<br />
neue Tupel<br />
• Achtung! Tupel kann veränderliche<br />
Werte als Tupelelemente haben<br />
Tupel sind Sequenzen<br />
• Geordnet<br />
• Klare Menge unterstützter<br />
Operationen<br />
• Sequenz von Werten beliebigen Typs<br />
im Gegensatz zu Strings (nur Zeichen)<br />
1 >>> tup = (1,2,3)<br />
2 >>> tup[1] = "zwei"<br />
3 Traceback (most recent call last):<br />
4 File "", line 1, in <br />
5 TypeError: ’tuple’ object does not<br />
6 support item assignment<br />
7 >>> tup = (1, [], 3)<br />
8 >>> tup[1].append("zwei")<br />
9 >>> tup<br />
10 (1, [’zwei’], 3)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 147 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Listen<br />
Listen – Sequenz<br />
Syntax wie Tupel<br />
• Umschlossen mit [ und ]<br />
• Keine spezielle Syntax mehr für<br />
einelementige Listen<br />
• Leere Liste mit []<br />
Beliebig kombinierbar und schachtelbar<br />
• Auch mit Tupel<br />
Sonst wie Tupel<br />
1 >>> [1, 2, 3]<br />
2 [1, 2, 3]<br />
3 >>> [1], []<br />
4 [1], []<br />
5 >>> [1, [2, "zwei"], (3, "drei")]<br />
6 [1, [2, ’zwei’], (3, ’drei’)]<br />
7 >>> lis = [1, [2, "zwei"], (3, "drei")]<br />
8 >>> lis[0]<br />
9 1<br />
10 >>> lis[1:]<br />
11 [[2, ’zwei’], (3, ’drei’)]<br />
12 >>> lis[2][0], len(lis)<br />
13 (3, 3)<br />
14 >>> lis + [4,5]<br />
15 [1, [2, ’zwei’], (3, ’drei’), 4, 5]<br />
16 >>> 1 in lis<br />
17 True<br />
18 >>> (lis*2)[1:-2]<br />
19 [[2, ’zwei’], (3, ’drei’), 1]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 148 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Listen<br />
Listen – Veränderliche Sequenz<br />
Ändern<br />
• Zuweisung von Teilen<br />
• Löschen<br />
Kopien und Zuweisung<br />
• Operationen erzeugen Kopien<br />
• Nachträgliches Verändern der<br />
Parameter ohne Einfluss<br />
Flache Kopien<br />
• Kopien nur auf oberster Ebene<br />
• Erzeugen neuer Listenstruktur<br />
• Die Elemente werden nicht kopiert,<br />
sondern nur Referenzen<br />
• Ändern der Elemente ist sichtbar<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> lis[0] = "eins"<br />
3 >>> lis<br />
4 [’eins’, 2, 3]<br />
5 >>> del lis[0]<br />
6 >>> lis<br />
7 [2, 3]<br />
1 >>> lis, kat = ["a", "b"], ["c", "d"]<br />
2 >>> lk = lis + kat<br />
3 >>> lk<br />
4 [’a’, ’b’, ’c’, ’d’]<br />
5 >>> lis[0] = "X"<br />
6 >>> lis, lk<br />
7 ([’X’, ’b’], [’a’, ’b’, ’c’, ’d’])<br />
8 >>> tup = (lis, kat)<br />
9 >>> tup<br />
10 ([’X’, ’b’], [’c’, ’d’])<br />
11 >>> lis[1] = "Y"<br />
12 >>> tup<br />
13 ([’X’, ’Y’], [’c’, ’d’])<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 149 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Listen<br />
Listen – Zuweisungen<br />
Zuweisungskompatibilität<br />
• Sequenzen sind untereinander<br />
zuweisungskompatibel<br />
Slice-Zuweisung möglich<br />
• Der Bereich wird durch Sequenz als<br />
Liste ersetzt<br />
Destruktive Methoden<br />
• append und extend ändern gegebene<br />
Liste, kein Rückgabewert<br />
• del ändert Liste<br />
• Zuweisung an Index ändert Liste<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> lis[1:2] = ("zwei", "two")<br />
3 >>> lis<br />
4 [1, ’zwei’, ’two’, 3]<br />
5 >>> lis[1:2] = ["zwei", "two"]<br />
6 >>> lis<br />
7 [1, ’zwei’, ’two’, ’two’, 3]<br />
8 >>> lis.append(4)<br />
9 >>> lis<br />
10 [1, ’zwei’, ’two’, ’two’, 3, 4]<br />
11 >>> lis.extend([5, 6])<br />
12 >>> lis<br />
13 [1, ’zwei’, ’two’, ’two’, 3, 4, 5, 6]<br />
14 >>> del lis[1:3]<br />
15 >>> lis<br />
16 [1, ’two’, 3, 4, 5, 6]<br />
17 >>> lis[1] = 2<br />
18 >>> lis<br />
19 [1, 2, 3, 4, 5, 6]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 150 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Listen<br />
Listen – Weitere Methoden<br />
range generiert Zahlenliste<br />
• Anfang, erstes Argument, optional<br />
(default 0)<br />
• Ende, zweites Argument<br />
• Schrittweite, drittes Argument, optional<br />
(default 1)<br />
Weitere destruktive Methoden<br />
• pop, insert<br />
Kellerverhalten und mehr<br />
• reverse, sort, sorted<br />
klassische Listenoperationen<br />
1 >>> lis = [4, 3, 2.5, 2, 1, 0, -1]<br />
2 >>> sorted(lis)<br />
3 [-1, 0, 1, 2, 2.5, 3, 4]<br />
4 >>> lis.sort(); lis<br />
5 [-1, 0, 1, 2, 2.5, 3, 4]<br />
1 >>> range(5)<br />
2 [0, 1, 2, 3, 4]<br />
3 >>> range(1, 5)<br />
4 [1, 2, 3, 4]<br />
5 >>> range(0, 50, 10)<br />
6 [0, 10, 20, 30, 40]<br />
7 >>> lis = range(5)<br />
8 >>> lis.append(5); lis<br />
9 [0, 1, 2, 3, 4, 5]<br />
10 >>> lis.pop()<br />
11 5<br />
12 >>> lis<br />
13 [0, 1, 2, 3, 4]<br />
14 >>> lis.insert(0, -1); lis<br />
15 [-1, 0, 1, 2, 3, 4]<br />
16 >>> lis.insert(4, 2.5); lis<br />
17 [-1, 0, 1, 2, 2.5, 3, 4]<br />
18 >>> lis.reverse(); lis<br />
19 [4, 3, 2.5, 2, 1, 0, -1]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 151 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Listen<br />
Listen – Eine weitere Sequenz, veränderlich<br />
Listen sind veränderlich<br />
• Sequenz-Operationen<br />
unveränderlicher Operationen mit<br />
Listen erzeugen neue Listen auf<br />
oberster Ebene<br />
• Spezielle destruktive<br />
Listen-Operationen, ohne Wert<br />
Listen sind Sequenzen<br />
• Ähnlich zu Feld (ArrayList) in Java<br />
• Laufzeitverhalten ähnlich zu Feld<br />
Warum Listen und Tupel?<br />
• Bei gemischten Typen eher Tupel;<br />
bei Liste möglich, nicht intuitiv<br />
• Unveränderliches Tupel effizienter<br />
• Tupel kann als Schlüssel im<br />
Wörterbuch genutzt werden<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> lis[1] = "zwei"<br />
3 >>> lis<br />
4 [1, ’zwei’, 3]<br />
5 >>> lis.append(4)<br />
6 >>> lis<br />
7 [1, ’zwei’, 3, 4]<br />
1 >>> (1, "ab")<br />
2 (1, ’ab’)<br />
3 >>> [1, "ab"]<br />
4 [1, ’ab’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 152 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Wörterbücher<br />
Dictionaries, Wörterbücher<br />
Dictionary, Wörterbuch<br />
• Abbildung unveränderlicher Werte<br />
(Schlüssel) auf beliebigen Werten<br />
• Syntax für Zugriff und Zuweisung wie<br />
beim Feld<br />
• Realisiert über Hashing<br />
Vorteile<br />
• Verwendung einfach und intuitiv<br />
11<br />
• Schlüssel nicht beschränkt auf Zahlen >>> dic.keys()<br />
12 [’eggs’, ’spam’]<br />
• Keine Feldgröße notwendig<br />
13 >>> dic.values()<br />
Dictionaries und Sequenzen<br />
14 [42, 3]<br />
• Schlüsselmenge (Sequenz),<br />
Wertemenge und Tupelmenge<br />
Schlüssel/Wert erzeugbar<br />
• Test auf Enthaltensein gegen<br />
Schlüsselmenge<br />
1 >>> dic = {}<br />
2 >>> dic = { ’spam’ : 2 }<br />
3 >>> dic[’spam’]<br />
4 2<br />
5 >>> dic[’spam’] = 3<br />
6 >>> dic<br />
7 {’spam’: 3}<br />
8 >>> dic[’eggs’] = 42<br />
9 >>> dic<br />
10 {’eggs’: 42, ’spam’: 3}<br />
15 >>> dic.items()<br />
16 [(’eggs’, 42), (’spam’, 3)]<br />
17 >>> ’eggs’ in dic<br />
18 True<br />
19 >>> dic.has_key(’spam’)<br />
20 True<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 153 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Wörterbücher<br />
Dictionaries – Builtins und Schlüsseleigenschaften<br />
Eingebaute Funktionen<br />
• len für Anzahl Schlüssel<br />
• del zum Löschen<br />
• Keine Slicing-Operationen<br />
Dictionary ist keine Sequenz<br />
Schlüssel unveränderlich<br />
• Intern mit Hashing realisiert<br />
• Zahlen, Strings, etc.<br />
• Tupel (auch tiefe Strukturen) sind<br />
erlaubt<br />
Ausnahme bei nicht vorhandenem<br />
Schlüssel<br />
1 >>> dic = {’eggs’: 42, ’spam’: 3}<br />
2 >>> len(dic)<br />
3 2<br />
4 >>> del dic[’eggs’]; dic<br />
5 {’spam’: 3}<br />
6 >>> dic[0:]<br />
7 Traceback (most recent call last):<br />
8 File "", line 1, in <br />
9 TypeError: unhashable type<br />
10 >>> dic[(1,2)] = ’tupel’<br />
11 >>> dic<br />
12 {(1, 2): ’tupel’, ’spam’: 3}<br />
13 >>> dic[[1,2]] = ’liste’<br />
14 Traceback (most recent call last):<br />
15 File "", line 1, in <br />
16 TypeError: unhashable type: ’list’<br />
17 >>> dic[’cheese’]<br />
18 Traceback (most recent call last):<br />
19 File "", line 1, in <br />
20 KeyError: ’cheese’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 154 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Wörterbücher<br />
Dictionaries – Veränderliche Abbildungen<br />
Dictionaries sind veränderlich<br />
• Zuweisung mit neuem Schlüssel fügt neue Elemente hinzu<br />
• Zuweisung mit existierendem Schlüssel überschreibt Wert<br />
• del löscht Schlüssel/Wert Zuordnung<br />
Dictionaries sind die einzigen Abbildungen<br />
• Ungeordnet (keine Sequenz), Zugriff nur über Schlüssel<br />
• Feste Menge von unterstützten Operationen<br />
• Zugriff zu beliebigen Objekten beliebigen Typs (Werte)<br />
• Zugriff über beliebige unveränderliche Objekte (Schlüssel)<br />
• Unveränderlicher Schlüssel<br />
• Wegen interner Implementierung mit Hashing<br />
• Sonst würde man Wert nicht wiederfinden<br />
• Siehe Algorithmen und Datenstrukturen<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 155 / 326
<strong>Programmieren</strong> in Python<br />
Kollektionen, Mengen<br />
Mengen – Veränderlich, keine Reihenfolge<br />
Mengen<br />
• Keine doppelten Elemente<br />
• Keine Reihenfolge, keine Sequenz<br />
• Realisiert wie Dictionaries,<br />
nur ist der Wert egal<br />
Eingebaute Funktionen und Operationen<br />
• len für Anzahl Elemente<br />
• in für Test auf Enthaltensein<br />
• Mengenoperationen mit | und &<br />
1 >>> s = set()<br />
2 >>> s.add(1)<br />
3 >>> s<br />
4 set([1])<br />
5 >>> s.add(2); s.add(3)<br />
6 >>> s<br />
7 set([1, 2, 3])<br />
8 >>> s.add(2)<br />
9 >>> s<br />
10 set([1, 2, 3])<br />
11 >>> 2 in s<br />
12 True<br />
13 >>> 4 in s<br />
14 False<br />
15 >>> len(s)<br />
16 3<br />
17 >>> s | set([2,3,4])<br />
18 set([1, 2, 3, 4])<br />
19 >>> s & set([2,3,4])<br />
20 set([2, 3])<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 156 / 326
<strong>Programmieren</strong> in Python<br />
Dateien<br />
Dateien<br />
Modul os für Systemoperationen<br />
• chdir um Verzeichnis zu wechseln<br />
• getcwd um Verzeichnis anzuzeigen<br />
• Unix und Windows Notation<br />
Dateien<br />
•<br />
8<br />
file ist eigener Datentyp<br />
938848<br />
9 >>> inhalt[700539:700600]<br />
• Konstruktor mit Dateiname und<br />
10 "python\npython’s\npythons\npyx\npyx’s<br />
Bearbeitungsart (r lesen, w schreiben,<br />
11 \npyxes\nq\nqua\nquack\nquack’s\nq"<br />
a erweitern)<br />
12 >>> eingabe.close()<br />
• read zum Lesen der gesamten! Datei<br />
• readlines für String-Liste der Zeilen<br />
• close Schließen optional, über<br />
Garbage Collector<br />
• Schreiben funktioniert ähnlich<br />
1 >>> import os<br />
2 >>> os.chdir(’/usr/share/dict’)<br />
3 >>> os.getcwd()<br />
4 ’/usr/share/dict’<br />
5 >>> eingabe = file("words", "r")<br />
6 >>> inhalt = eingabe.read()<br />
7 >>> len(inhalt)<br />
13 >>> os.chdir(’/tmp’)<br />
14 >>> ausgabe = file(’wordskopie’, ’w’)<br />
15 >>> ausgabe.write(inhalt)<br />
16 >>> ausgabe.close()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 157 / 326
<strong>Programmieren</strong> in Python<br />
Typen<br />
Typ-Überprüfung und Konversion<br />
Test welcher Typ<br />
• type gibt Typ zurück<br />
• isinstance testet ob von Typ<br />
• Vergleich und Auswahl von Typen<br />
Typkonvertierung<br />
• Typname als Funktionsaufruf<br />
Typen<br />
• int, long, float, complex<br />
• str, list, tuple<br />
• dict, . . .<br />
Konversion von/zu Zeichen<br />
• Zeichen in Python keine Zahl,<br />
nicht vorhanden<br />
• ord und chr<br />
1 >>> type([])<br />
2 <br />
3 >>> lis = [1,2,3]; type(lis)<br />
4 <br />
5 >>> type(lis)==list, type(lis)==type({})<br />
6 True, False<br />
7 >>> isinstance(lis, list)<br />
8 True<br />
9 >>> int, long, float, complex<br />
10 (, ,<br />
11 , )<br />
12 >>> str, list, tuple, dict<br />
13 (, ,<br />
14 , )<br />
15 >>> int("12")<br />
16 12<br />
17 >>> list("123")<br />
18 [’1’, ’2’, ’3’]<br />
19 >>> ord(’A’), chr(65)<br />
20 (65, ’A’)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 158 / 326
<strong>Programmieren</strong> in Python<br />
Typen<br />
Die Doku ist Dein Freund<br />
Dokumentation<br />
• docs.python.org<br />
• Tutorial, sehr guter Einstieg<br />
• Bibliothek, die Referenz für<br />
alle eingebauten und<br />
anderen Objekte,<br />
Funktionen, Module<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 159 / 326
<strong>Programmieren</strong> in Python<br />
Variablen<br />
Variablen<br />
Verwendung<br />
• Müssen nicht deklariert werden<br />
• Müssen vor erster Verwendung<br />
initialisiert werden<br />
Typ, dynamisch und streng<br />
• Dynamische Typisierung, Variable an<br />
alles bindbar<br />
• Strenge Typisierung, Gebundenes<br />
Objekt hat Typ<br />
Syntaxspezialitäten<br />
• Zuweisung hat keinen Wert<br />
• Mehrfachzuweisung möglich<br />
• Tupelzuweisung<br />
Gültige Variablenbezeichner wie in Java,<br />
keine Schlüsselwörter<br />
1 >>> x = 3<br />
2 >>> x<br />
3 3<br />
4 >>> y<br />
5 NameError: name ’y’ is not defined<br />
6 >>> x = 3<br />
7 >>> x = "Hallo"<br />
8 >>> x = 3; x + 3<br />
9 6<br />
10 >>> x = "3"; x + 3<br />
11 TypeError: cannot concatenate<br />
12 ’str’ and ’int’ objects<br />
1 >>> x = y = 3<br />
2 >>> x, y = 3, 4<br />
3 >>> x, y<br />
4 (3, 4)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 160 / 326
<strong>Programmieren</strong> in Python<br />
Variablen<br />
Zuweisung und Ausdrücke<br />
Gleichheit und Identität<br />
• Alles ist ein Objekt<br />
• Gleichheit ==, Objektidentität is<br />
Zuweisung<br />
• Variablen sind Namen, die an Objekte<br />
gebunden sind<br />
• Rechte Seite einer Zuweisung gibt<br />
Objekt (vorhandenes oder neues)<br />
9<br />
10<br />
[1, 2, 3]<br />
>>> lis = [1, 2, 3]<br />
zurück<br />
11 >>> kat = lis[:] # Kopie<br />
12 >>> lis == kat, lis is kat<br />
• Linke Seite einer Zuweisungen ist eine13 (True, False)<br />
Name an den Objekt gebunden wird<br />
Ausdrücke evaluieren zu neuen Objekten<br />
• Die Sequenz von Anfang bis Ende ist<br />
ein Ausdruck<br />
• [:] macht eine (flache) Kopie<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> kat = [1, 2, 3]<br />
3 >>> lis == kat, lis is kat<br />
4 (True, False)<br />
5 >>> lis.append(4)<br />
6 >>> lis<br />
7 [1, 2, 3, 4]<br />
8 >>> kat<br />
lis<br />
kat<br />
1 2 3<br />
1 2 3<br />
4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 161 / 326
<strong>Programmieren</strong> in Python<br />
Variablen<br />
Referenzsemantik<br />
Referenzsemantik<br />
• Variablen sind Namen, die an Objekte<br />
gebunden sind<br />
• Rechte Seite einer Zuweisung gibt<br />
Objekt (vorhandenes oder neues)<br />
zurück<br />
• Linke Seite einer Zuweisungen ist eine<br />
Name an den Objekt gebunden wird<br />
Namen evaluieren zu dem gebundenem<br />
Objekt<br />
• Änderungen von Objekten über alle<br />
Referenzen sichtbar<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> kat = lis<br />
3 >>> lis == kat, lis is kat<br />
4 (True, True)<br />
5 >>> lis.append(4)<br />
6 >>> lis<br />
7 [1, 2, 3, 4]<br />
8 >>> kat<br />
9 [1, 2, 3, 4]<br />
lis<br />
kat<br />
1 2 3<br />
4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 162 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – Verzweigung<br />
Verzweigung<br />
• Schlüsselwörter: if, elif, else<br />
• : Ausdruck, der als<br />
Wahrheitswert interpretiert wird<br />
• : Beliebige Folge von<br />
Anweisungen<br />
Syntax<br />
• Bedingung endet mit Doppelpunkt,<br />
Keine Klammern notwendig<br />
• ACHTUNG! Einrückung ist signifikant<br />
und Teil der Syntax<br />
• Block durch Einrücktiefe bestimmt<br />
• Einrückung Tabulator oder gleiche<br />
Anzahl an Leerzeichen<br />
• Keine (geschweiften) Klammern!<br />
Einzeiler möglich, vermeiden<br />
if :<br />
<br />
[elif :<br />
]*<br />
[else:<br />
]<br />
1 if 0 == 0:<br />
2 print "ja"<br />
3 if "nichtleerer String":<br />
4 print "ja"<br />
5 else:<br />
6 print "nein"<br />
7 if 0:<br />
8 print "eins"<br />
9 print "zwei"<br />
10 print "drei"<br />
11 if 1: print "eins"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 163 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
if/else Ausdruck statt ?-Operator<br />
Syntax ungewöhnlich<br />
• Erst Ergebniswert im “normalen”<br />
Fall<br />
• Dann Bedingung<br />
• Dann “alternativer” Fall<br />
Alternative mit booleschem<br />
Ausdruck<br />
• and und or evaluieren nur so<br />
weit wie notwendig<br />
• Nachbau mit and/ormöglich<br />
• Problematisch wenn “normaler”<br />
Wert äquivalent zu falsch ist<br />
• Nicht mehr statt if/else<br />
verwenden<br />
if else <br />
// in Java, C<br />
? : <br />
1 >>> x, y = 1, 2<br />
2 >>> e = "kleiner" if x>> e<br />
4 ’kleiner’<br />
and or <br />
1 >>> x, y = 1, 2<br />
2 >>> e = x>> e<br />
4 ’kleiner’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 164 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – while-Schleife<br />
while-Schleife<br />
• Schlüsselwörter: while, else, break,<br />
continue, pass<br />
• else-Zweig nur, wenn Schleife ohne<br />
break verlassen wurde<br />
• pass, leere Anweisung, macht nichts,<br />
Ersatz für {}<br />
Syntax<br />
• Wieder Einrücken als integraler<br />
Bestandteil der Schleifensyntax<br />
while :<br />
<br />
[else:<br />
]<br />
1 lis = [1, 2, 3, 4]<br />
2 while lis:<br />
3 print lis.pop()<br />
4 else:<br />
5 print "Ende"<br />
4<br />
3<br />
2<br />
1<br />
Ende<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 165 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – for-Schleife<br />
for-Schleife<br />
• Schlüsselwörter: for, in, break,<br />
continue, pass<br />
• Iterieren über Elemente in Sequenzen<br />
• in wählt Elemente aus Sequenz<br />
sukzessive aus und weist sie je<br />
Durchlauf der Variable zu<br />
• Klassische Schleife über Indexe nur<br />
nach als Nachbau mit range<br />
range<br />
• range(von, bis, step)<br />
• Erzeugt eine Liste von Zahlen von<br />
inklusive, bis exklusive<br />
• von optional, default 0<br />
• step optional, default 1<br />
for in :<br />
<br />
[else:<br />
]<br />
1 for ele in ["Hallo", "Welt"]:<br />
2 print ele<br />
3 for idx in range(1, 4):<br />
4 print idx<br />
5 for ch in "Hi":<br />
6 print ch<br />
Hallo<br />
Welt<br />
1<br />
2<br />
3<br />
H<br />
i<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 166 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – for-Schleife, Dictionaries<br />
for-Schleife und Dictionaries<br />
• Fragt Objekte, ob sie auch eine<br />
Sequenz sein können<br />
• Das Dictionary sagt, ja, dann bin ich<br />
eine Sequenz der Schlüssel<br />
• Dann wird über die Schlüssel iteriert<br />
Auch nett mit items und Tupelzuweisung<br />
1 dic = { 1: ’eins’, 2: ’zwei’ }<br />
2 for key in dic: # wie dic.keys()<br />
3 print key, dic[key]<br />
1 eins<br />
2 zwei<br />
1 dic = { 1: ’eins’, 2: ’zwei’ }<br />
2 print dic.items()<br />
3 for key, value in dic.items():<br />
4 print key, value<br />
[(1, ’eins’), (2, ’zwei’)]<br />
1 eins<br />
2 zwei<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 167 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – for-Schleife, typischer Einsatz<br />
Klassische for-Schleife<br />
• Durchlaufen von Index-Werten<br />
• Sequenz von Index-Werten, mit range<br />
erzeugt<br />
• Selten benötigt<br />
• Java/C Idiom, weniger Python<br />
Feldzugriff vermeiden<br />
• Keine expliziten Indexvariablen<br />
• Eleganter<br />
• Kein Indexfehler möglich!<br />
• Funktioniert für alle Sequenzen<br />
1 for idx in range(100): # 0-99 in Python<br />
2 print idx<br />
1 // 0-99 in Java<br />
2 for(int i=0; i < 100; i+=1) {<br />
3 System.out.println(idx);<br />
4 }<br />
1 for ele in arr: # Feldzugriff in Python<br />
2 print ele<br />
1 // Feldzugriff in Java<br />
2 for(int i=0; i < arr.length; i+=1) {<br />
3 System.out.println(arr[i]);<br />
4 }<br />
1 for e in (0, 1, 2, 3): # alle Sequenzen<br />
2 print e<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 168 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Schleifenbeispiel – Dateiinhalte durchlaufen<br />
Dateien mit while<br />
• Endlosschleife mit break<br />
• Einlesen bis Fehlschlag<br />
• Schließen optional, aber guter Stil<br />
Dateien mit for<br />
• Eleganter<br />
• Alles Einlesen in eine Liste<br />
Noch Eleganter<br />
• Default Datei-Aktion ist lesen<br />
• Default ist zeilenweise einlesen<br />
• Automatisch schließen, da offene<br />
Datei nicht gebunden<br />
1 # C-Style :-(<br />
2 eingabe = file("dat.txt", "r")<br />
3 while True:<br />
4 line = eingabe.readline()<br />
5 if not line:<br />
6 break<br />
7 print line<br />
8 eingabe.close()<br />
1 # Besser :-|<br />
2 eingabe = file("dat.txt", "r")<br />
3 for line in eingabe.readlines():<br />
4 print line<br />
5 eingabe.close()<br />
1 # Python-Style :-)<br />
2 for line in file("dat.txt"):<br />
3 print line<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 169 / 326
<strong>Programmieren</strong> in Python<br />
Kontrollstrukturen<br />
Hinweise zu Kontrollstrukturen<br />
Beim Editieren<br />
• Vergessen Sie die Doppelpunkte nicht<br />
• Beginnen Sie immer in der ersten Spalte<br />
• Rücken Sie konsistent ein (nur Leerzeichen oder nur Tabulatoren)<br />
• Rücken Sie immer gleich weit ein (4 Zeichen)<br />
• Oder am besten alles mit der IDLE<br />
Leerzeilen beenden im interaktiven Modus einen Anweisungsblock<br />
Erwarten Sie nicht immer ein Ergebnis<br />
• Beispiel: append<br />
Schreiben Sie nicht Java/C in Python!<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 170 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Funktionen<br />
Definition mit def<br />
• Erstellt Funktionsobjekt und bindet<br />
Namen daran<br />
• return für Rückgabe, ansonsten<br />
automatisch None<br />
• Eins oder mehrere<br />
Argumente/Parameter werden<br />
per Namensbindung übergeben<br />
def ([ [, ...]]):<br />
[]<br />
<br />
[return ]<br />
1 def mult(x, y):<br />
2 "Multipliziere zwei Objekte x, y"<br />
3 return x*y<br />
• Dokumentationsstring <br />
eingebaut, optionale erste Zeile<br />
Auch interaktiv eingebbar<br />
• Leerzeile zum Beenden<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 171 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Funktionen – Beispiel, intersect<br />
Ziel<br />
• Schnittmenge von Sequenzen<br />
• Abstraktion als Funktion<br />
Lösung<br />
• Python-Funktion intersect<br />
• Ergebnis initial eine leere Sequenz<br />
• Für alle Elemente in erster Sequenz<br />
• Suche dieses Element in zweiter<br />
Sequenz<br />
• Wenn vorhanden, dann ist es ein<br />
gemeinsames Element; füge es zum<br />
Ergebnis hinzu<br />
• Gib Ergebnis zurück<br />
Beispiele<br />
• Strings, Listen, Tupel sind Sequenzen<br />
1 def intersect(seq1, seq2):<br />
2 """Schnittmenge von Sequenzen<br />
3 seq1 und seq2"""<br />
4 res = []<br />
5 for ele in seq1:<br />
6 if ele in seq2:<br />
7 res.append(ele)<br />
8 return res<br />
1 >>> intersect("spam", "scam")<br />
2 [’s’, ’a’, ’m’]<br />
3 >>> intersect([1,2,3], (4,2,6))<br />
4 [2]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 172 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Gültigkeitsbereiche in Funktionen<br />
Funktionsaufrufe sind Namensraum<br />
• Jeder Funktionsaufruf bietet einen<br />
neuen Gültigkeitsbereich<br />
(Namensraum)<br />
• Die Definition auch<br />
Beispiel f, g<br />
• Variable g wird nicht verändert<br />
• Weder bei der Definition<br />
• Noch bei dem Aufruf<br />
• g in der Funktion ist eine neue lokale<br />
Variable<br />
1 >>> g = 1<br />
2 >>> def f(x, y):<br />
3 g=2<br />
4 return x+y<br />
5<br />
6 >>> g<br />
7 1<br />
8 >>> f(5, 6)<br />
9 11<br />
10 >>> g<br />
11 1<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 173 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Gültigkeitsbereiche in Funktionen – Durchgriff<br />
Durchgriff auf globale Variable<br />
• Schlüsselwort global<br />
• Variable vom “globalen” Namensraum<br />
wird verwendet<br />
• Durchgriff immer nur auf äußerste<br />
“globale” Ebene möglich<br />
• Wenn möglich vermeiden*<br />
1 >>> g = 1<br />
2 >>> def f(x, y):<br />
3 global g<br />
4 g=2<br />
5 return x+y<br />
6<br />
7 >>> g<br />
8 1<br />
9 >>> f(5, 6)<br />
10 11<br />
11 >>> g<br />
12 2<br />
*Bei OpenGL muss man dann leider doch mal ab<br />
und zu. . .<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 174 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Gültigkeitsbereiche Funktionen – Überschreiben<br />
Überschreiben Global/lokal Eigenschaft<br />
• Überschreiben der global/lokal<br />
Eigenschaft nicht möglich<br />
• In f1 ist g als Parameter lokal, kann<br />
nicht auch global sein<br />
Nur lesen automatisch möglich<br />
• Direkter Zugriff auf globalen<br />
Namensraum möglich wie in f2<br />
• Syntaktisch ok, stilistisch unschön<br />
Nachträglich global machen<br />
• Wenn vorher nur gelesen wurde, dann<br />
wurde globaler Wert gelesen, f3<br />
• Wenn vorher geschrieben wurde, dann<br />
geht lokaler Wert verloren, f4<br />
• Warnung: unschön, vermeiden<br />
1 >>> def f1(x, g):<br />
2 global g<br />
3 SyntaxError: name ’g’ is local and global<br />
1 >>> g = 1<br />
2 >>> def f2(x, y):<br />
3 return g+1<br />
4 >>> f2(5, 6)<br />
5 2<br />
1 >>> def f3(x):<br />
2 y = g<br />
3 global g<br />
4 SyntaxWarning: name ’g’ is used<br />
5 prior to global declaration<br />
6 >>> def f4(x):<br />
7 g = 3<br />
8 global g<br />
9 SyntaxWarning: name ’g’ is<br />
10 assigned to before global<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 175 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Regeln für Gültigkeitsbereiche<br />
Lokal<br />
• Jeder Funktionsaufruf bietet einen<br />
neuen lokalen Gültigkeitsbereich<br />
(Namensraum)<br />
• Jeder Aufruf, Rekursion funktioniert<br />
• Zugewiesene Namen sind lokal im<br />
aktuellen Gültigskeitsbereich<br />
• können explizit global werden<br />
• Blöcke (Einrückungen) sind kein<br />
eigener Gültigkeitsbereich<br />
Global<br />
• Das einschließende Modul ist ein<br />
globaler Gültigkeitsbereich<br />
• Der interaktive Modus ist ein Modul,<br />
hat den Namen ’__main__’<br />
Reservierte Namen sind Teil der Sprache<br />
Reserviert<br />
Modul<br />
Modul<br />
Funktionsdefinition<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsdefinition<br />
Funktionsdefinition<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 176 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Namensauflösung, LGB-Regel<br />
Namen in drei Bereichen suchen<br />
• Erst Lokal<br />
zum Beispiel Variablen und Parameter<br />
in def<br />
• Dann Global<br />
zum Beispiel Funktionsdefinition,<br />
Variablen auf oberster Ebene<br />
• Dann eingeBaute<br />
builtin, reservierte Namen, zum<br />
Beispiel len, file<br />
Namensbindungen<br />
• In Funktionen lokal<br />
• In Moduln global<br />
• Für reservierte Namen vermeiden<br />
1 >>> a,b = 1,2<br />
2 >>> def f():<br />
3 a = 3<br />
eingeBaut<br />
4 print a,b<br />
5 >>> f()<br />
6 3 2<br />
7 >>> a,b<br />
8 (1, 2)<br />
Global<br />
Lokal<br />
9 >>> list = "kein Typ mehr, vermeiden"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 177 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Parameterübergabe<br />
Parameterübergabe ist Namensbindung<br />
• Parameternamen werden an<br />
übergebene Objekte gebunden<br />
• Neue lokale Namen<br />
• Bindung von Namen an Objekt<br />
beeinflusst Objekt nicht<br />
Verwendung<br />
• Call by Reference<br />
• Das Ändern eines änderbaren Objekts<br />
hat Auswirkungen (Seiteneffekte)<br />
• Bei unveränderlichen Objekten kann<br />
es keine Auswirkungen haben, wie call<br />
by value<br />
1 def aendern(x, y):<br />
2 x = 2<br />
3 y[1] = 1<br />
1 >>> x, y = ([1,2], [3,4])<br />
2 >>> aendern(x, y)<br />
3 >>> x, y<br />
4 ([1, 2], [3, 1])<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 178 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Parameterübergabe – Vorgabewerte<br />
Vorgabewerte (Default)<br />
• Vorgabewert kann optional bei jedem<br />
Parameter angegeben werden<br />
• Zusätzlich = und Ausdruck, der zu<br />
Vorgabewert evaluiert<br />
• Parameter mit Vorgabewerten hinter<br />
die Parameter ohne Vorgabewerte<br />
• Stellungsparameter,<br />
Positionsparameter<br />
Aufruf<br />
• Wert für Parameter mit Vorgabewert<br />
kann weggelassen werden<br />
• Falls Wert weggelassen, wird<br />
Vorgabewert eingesetzt<br />
1 def ink(x, a=1):<br />
2 return x+a<br />
1 >>> ink(3)<br />
2 4<br />
3 >>> ink(3, 1)<br />
4 4<br />
5 >>> ink(3, 17)<br />
6 20<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 179 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Vorgabewerte – Anwendungsbeispiel<br />
Suche von Elementen in Sequenz<br />
• Vorgabewerte für start und ende<br />
des Suchbereichs<br />
• Sinnvolle Vorgabe ist 0 für start<br />
und Länge der Sequenz für ende<br />
Nutzung<br />
• Automatische Belegung von<br />
links nach rechts<br />
• Ergänzung nach Position,<br />
um ende zu übergeben muss<br />
man auch start übergeben<br />
1 def suche(seq, ele, start=0, ende=None):<br />
2 if ende is None:<br />
3 ende = len(seq)<br />
4 for pos in range(start, ende):<br />
5 if seq[pos] == ele:<br />
6 return pos<br />
1 >>> suche([1,2,3,4,5,6], 3)<br />
2 2<br />
3 >>> suche([1,2,3,4,5,6], 3, 0)<br />
4 2<br />
5 >>> suche([1,2,3,4,5,6], 3, 4)<br />
6 >>> suche([1,2,3,4,5,6], 3, 0, 6)<br />
7 2<br />
8 >>> suche([1,2,3,4,5,6], 3, 0, 1)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 180 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Vorgabewerte – Besonderheiten<br />
Gültigkeit<br />
1<br />
2<br />
def suche(seq,ele,start=0,ende=len(seq)):<br />
for pos in range(start, ende):<br />
• Parametername während der<br />
3<br />
Definition der Vorgabewerte noch nicht 4<br />
...<br />
Traceback (most recent call last):<br />
nutzbar<br />
5 File "", line 1, in <br />
• Umgehen durch Markieren mit None<br />
und dynamische Berechnung<br />
Lebenszyklus<br />
• Vorgabewert wird nur einmal<br />
ausgewertet, bei der<br />
Funktionsdefinition<br />
• Überraschungen bei änderbaren<br />
Vorgabewerten<br />
• Änderungen bleiben über Aufrufe<br />
hinweg enthalten<br />
• Vermeiden durch Markieren mit None<br />
und dynamische Berechnung<br />
6 NameError: name ’seq’ is not defined<br />
1 >>> def oh(l, a=[]):<br />
2 a.append("ende")<br />
3 return l+a<br />
4 >>> oh([1,2],[3,4])<br />
5 [1, 2, 3, 4, ’ende’]<br />
6 >>> oh([1,2],[3,4,5])<br />
7 [1, 2, 3, 4, 5, ’ende’]<br />
8 >>> oh([1,2])<br />
9 [1, 2, ’ende’]<br />
10 >>> oh([1,2])<br />
11 [1, 2, ’ende’, ’ende’]<br />
12 >>> oh([1,2])<br />
13 [1, 2, ’ende’, ’ende’, ’ende’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 181 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Parameterübergabe mit Schlüsselwort<br />
Ziel<br />
• Viele Vorgabewerte verwenden, aber<br />
einige Parameter anders<br />
• Zwang Angabe aller früheren<br />
Parameter auflösen<br />
Schlüsselwortparameter<br />
• Parameter über Namen zuweisen<br />
• Name des Parameters als linke Seite<br />
einer Zuweisung im Aufruf<br />
• Reihenfolge der Parameter beliebig<br />
• Für alle Argumente außer den<br />
Schlüsselwortparametern Vorgabe<br />
• Parameter ohne Vorgabewert müssen<br />
als Positions- oder Schlüsselwortparameter<br />
übergeben werden<br />
1 def suche(seq, ele, start=0, ende=None):<br />
2 if ende is None:<br />
3 ende = len(seq)<br />
4 for pos in range(start, ende):<br />
5 if seq[pos] == ele:<br />
6 return pos<br />
1 >>> lis = [1, 2, 3, 4, 5, 6]<br />
2 >>> suche(lis, 2, start=0, ende=len(lis))<br />
3 1<br />
4 >>> suche(lis, 2, 0, len(lis))<br />
5 1<br />
6 >>> suche(lis, 2, ende=len(lis))<br />
7 1<br />
8 >>> suche(lis, 2, start=1, ende=len(lis))<br />
9 1<br />
10 >>> suche(lis, ende=len(lis), ele=2)<br />
11 1<br />
12 >>> suche(lis, 2, ende=1)<br />
13 >>><br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 182 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Argumente sammeln mit * und **<br />
Weitere Positionsparameter *<br />
• Eine Variable am Ende kann mit einem<br />
Stern * versehen werden<br />
• In dieser Variable werden dann alle<br />
weiteren Positionsparameter<br />
gesammelt als Tupel gesammelt<br />
• Realisiert beliebig viele Parameter, wie<br />
zum Beispiel print<br />
Weitere Schlüsselwortparameter **<br />
• Eine Variable ganz am Ende kann mit<br />
zwei Sternen ** versehen werden<br />
11 SyntaxError: non-keyword arg after<br />
• Darin werden alle weiteren<br />
12 keyword arg<br />
Schlüsselwortparameter als Dictionary<br />
gesammelt<br />
• Die Schlüssel sind die<br />
Variablennamen als Strings<br />
1 def params(x, y, *pos, **key):<br />
2 print x, y, pos, key<br />
1 >>> params(1, 2)<br />
2 1 2 () {}<br />
3 >>> params(1, 2, 3, 4, 5)<br />
4 1 2 (3, 4, 5) {}<br />
5 >>> params(1, 2, 3, 4, drei=3, vier=4)<br />
6 1 2 (3, 4) {’drei’: 3, ’vier’: 4}<br />
7 >>> params(1, 2, 3, 4, vier=4, fuenf=5)<br />
8 1 2 (3, 4) {’fuenf’: 5, ’vier’: 4}<br />
9 >>> params(1, 2, 3, fuenf=5, 4, vier=4)<br />
10 File "", line 1<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 183 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Funktionen in Funktionen und die LEGB-Regel<br />
Funktionsdefinitionen während<br />
Funktionsausführung<br />
• Sind erlaubt und sinnvoll<br />
• Umfassen aktuellen Namensraum und<br />
halten ihn fest (Enclosing)<br />
• Von innen nach außen<br />
LEGB-Regel<br />
• LGB-Regel erweitert<br />
• Zwischen Lokal und Global<br />
• Man sucht im umschließenden<br />
Namensraum, in dem die Funktion<br />
definiert wurde<br />
• Dies ist entweder der globale<br />
Namensraum oder ein anderer<br />
Funktionsaufruf als Namensraum<br />
g 1 2 3<br />
e 6 5 3<br />
l 4 5 3<br />
eingeBaut<br />
1 x, y, z = 1, 2, 3<br />
2 def f():<br />
3 x, y = 4, 5<br />
4 def g():<br />
5 x = 6<br />
Global<br />
Eingekapselt<br />
Lokal<br />
6 print "e", x, y, z # 6, 5, 3<br />
7 g()<br />
8 print "l", x, y, z # 4, 5, 3<br />
9 print "g", x, y, z # 1, 2, 3<br />
10 f()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 184 / 326
<strong>Programmieren</strong> in Python<br />
Funktionen<br />
Design-Prinzipien für Funktionen<br />
Parameter verwenden<br />
• Keine globalen Variablen verwenden<br />
• Flexible Gestaltung der übergebbaren<br />
Parameter möglich<br />
• Reduziert Abhängigkeiten<br />
Rückgaben verwenden<br />
• Keine globalen Variablen verwenden<br />
• Modifikation von Parametern meiden<br />
• Mehrere Werte als Tupel zurückgeben<br />
• Modifikation ok in Klassen/Methoden<br />
Verschachtelte Funktionen mit Vorsicht<br />
• Definition einer Funktion in einer<br />
Funktion nur wenn notwendig<br />
• Anonyme Funktionen sind meist<br />
Alternative<br />
1 x, y = 1, 2<br />
2 def sehrboese():<br />
3 global x<br />
4 x = x*y<br />
5 sehrboese()<br />
6<br />
7 x, y = 1, 2<br />
8 def besser(x, y):<br />
9 return x*y<br />
10 x = besser(x, y)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 185 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Programmierung<br />
Anonyme Funktion, Lambda-Ausdrücke<br />
Funktionen sind auch Objekte<br />
• Funktionsobjekte sind normale<br />
Objekte, “first class citizens”<br />
• Funktionsnamen sind an<br />
Funktionsobjekte gebunden<br />
• Definition von Funktionsobjekten und<br />
Bindung an einen Namen mit def<br />
Funktionsobjekte<br />
• Erzeugen eines anonymen<br />
Funktionsobjekte mit lambda<br />
• lambda : <br />
• Funktion mit als Parameter<br />
• Wert der Funktion durch ,<br />
der verwendet<br />
• Zuweisung an Namen und Aufruf<br />
möglich<br />
1 >>> def ink(x):<br />
2 return x+1<br />
3 >>> ink(3)<br />
4 4<br />
5 >>> ink<br />
6 <br />
7 >>> x+1<br />
8 NameError: name ’x’ is not defined<br />
1 >>> lambda x: x+1<br />
2 <br />
3 >>> ink2 = lambda x: x+1<br />
4 >>> ink2<br />
5 <br />
6 >>> ink2(3)<br />
7 4<br />
8 >>> (lambda x: x+1)(3)<br />
9 4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 186 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Programmierung<br />
Funktionales <strong>Programmieren</strong><br />
Funktionales <strong>Programmieren</strong>,<br />
Funktionsaufrufe<br />
• Programm als applikativer<br />
Algorithmus, sukkzesive Reduktion<br />
von Ausdrücken<br />
• Nur Funktionsaufrufe, statt<br />
Kontrollstrukturen<br />
• Primitive zum flexiblen Aufrufen von 10 >>> apply(plus, tup)<br />
Funktionen mit Parametern notwendig<br />
Flexible Parameter<br />
• Erweitere Call Syntax<br />
• * für Positionsparameter, “ausbreiten”<br />
der Parameter<br />
1 >>> def plus(x, y):<br />
2 return x+y<br />
• ** für Schlüsselwortparameter<br />
18 >>> apply(plus, ptub + (4,))<br />
• Alternative: Eingebaute Funktion apply19 6<br />
für Positionsparameter<br />
3<br />
4 >>> tup = (2, 4)<br />
5 >>> plus(tup)<br />
6 TypeError: plus() takes exactly<br />
7 2 arguments (1 given)<br />
8 >>> plus(*tup)<br />
9 6<br />
11 6<br />
12 >>> ptup = (2, )<br />
13 >>> plus(*(ptup + (4,)))<br />
14 6<br />
15 >>> dic = {’x’:2, ’y’:4}<br />
16 >>> plus(**dic)<br />
17 6<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 187 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Funktionale Primitive – map<br />
Funktion auf allen Elementen<br />
• Für alle Objekte von Sequenzen eine<br />
Funktion anwenden<br />
• Schlüsselwort map<br />
6 [2, 3, 4]<br />
• Erster Parameter die Funktion<br />
7 >>> map(lambda x: x+3, [1, 2, 3])<br />
• Ab zweiten Parameter die Sequenzen, 8 [4, 5, 6]<br />
so viele Sequenzen wie die Funktion 9 >>> map(lambda x,y: x+y,<br />
Parameter hat<br />
10 [1, 2, 3], [4, 5, 6])<br />
11 [5, 7, 9]<br />
• Ergebnis ist Liste Funktionsergebnis je<br />
12 >>><br />
Element der Eingabesequenz<br />
• Kürzeste Sequenz bestimmt Länge<br />
des Ergebnisses<br />
Beispiele<br />
• Erhöhe alle Werte um 1<br />
• Addiere die Inhalte einer Liste<br />
paarweise<br />
1 >>> def ink(x):<br />
2 return x+1<br />
3 >>> map(ink, [1, 2, 3])<br />
4 [2, 3, 4]<br />
5 >>> map(lambda x: x+1, [1, 2, 3])<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 188 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Einsatzbeispiel für map<br />
Aufgabe<br />
• Berechne die Liste der Quadratzahlen<br />
von 1 bis 10<br />
Lösung<br />
• for-Schleife<br />
• Liste zusammenbauen<br />
• Zurückgeben<br />
Funktionale Lösung<br />
• Einzeiler mit map<br />
• Liste der Zahlen mit range<br />
• Quadrieren als Lambda-Funktion<br />
• Keine Schleifen<br />
1 def quadratzahlen(von=1, bis=10):<br />
2 lis = []<br />
3 for i in range(von, bis+1):<br />
4 lis.append(i*i)<br />
5 return lis<br />
6<br />
7 print quadratzahlen()<br />
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
1 def quadratzahlen(von=1, bis=10):<br />
2 return map(lambda x: x*x,<br />
3 range(von, bis+1))<br />
4<br />
5 print quadratzahlen()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 189 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
map illustriert<br />
1 2 3 2 3 4 4 8 16<br />
lambda x, y, z: x+y+z<br />
7 13 23<br />
1 >>> map(lambda x, y, z: x+y+z, [1, 2, 3], [2, 3, 4], [4, 8, 16])<br />
2 [7, 13, 23]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 190 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Funktionale Primitive – filter<br />
Nur Elemente für die Funktion ok ist<br />
• Für alle Objekte einer Sequenz eine<br />
Funktion anwenden, nur die<br />
durchlassen, für die der Funktionswert<br />
äquivalent zu wahr ist<br />
• Schlüsselwort filter<br />
• Erster Parameter die Funktion<br />
• Zweiter Parameter die Sequenz<br />
• Ergebnis ist Liste der ursprünglichen<br />
Elemente, deren Funktionswert<br />
äquivalent zu wahr ist<br />
Beispiele<br />
• Test ob Zahl größer 0<br />
• Test ob Zahl zwischen 1 und 2<br />
• Test ob gerade Zahl<br />
1 >>> def groesser0(x):<br />
2 return x>0<br />
3 >>> filter(groesser0, [1,-1,2,-2,3,-3,4])<br />
4 [1, 2, 3, 4]<br />
5 >>> filter(lambda x: x>0,<br />
6 [1, -1, 2, -2, 3, -3, 4])<br />
7 [1, 2, 3, 4]<br />
8 >>> filter(lambda x: x>0 and x>> filter(lambda x: x%2 == 0,<br />
12 [1, 2, 3, 4, 5])<br />
13 [2, 4]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 191 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Einsatzbeispiel für filter<br />
Aufgabe<br />
• Berechne die Liste der Primzahlen<br />
zwischen 2 und 100<br />
Lösung<br />
• for-Schleife<br />
• Liste zusammenbauen<br />
• Zurückgeben<br />
Funktionale Lösung<br />
• Einzeiler mit filter<br />
• Liste der Zahlen mit range<br />
• Funktion zum Testen ob Primzahl wie<br />
bei for-Schleife<br />
• Keine Schleifen<br />
1 def is_prim(zahl):<br />
2 for teiler in range(2, zahl):<br />
3 if zahl%teiler == 0:<br />
4 return False<br />
5 return True<br />
6 def prims():<br />
7 primzahlen = []<br />
8 for zahl in range(2, 100):<br />
9 if is_prim(zahl):<br />
10 primzahlen.append(zahl)<br />
11 return primzahlen<br />
12 print prims()<br />
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29,<br />
31, 37, 41, 43, 47, 53, 59, 61, 67,<br />
71, 73, 79, 83, 89, 97]<br />
1 def prims():<br />
2 return filter(is_prim, range(2, 100))<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 192 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Funktionale Primitive – reduce<br />
Alle Elemente einer Sequenz mit<br />
einer Funktion kombinieren<br />
• Kumuliere alle Objekte einer<br />
Sequenz über Funktionswerte<br />
auf (foldl)<br />
• Schlüsselwort reduce<br />
• Erster Parameter die Funktion<br />
1 >>> def add(x, y):<br />
2 return x+y<br />
3 >>> def summe(lis):<br />
4 ret = 0<br />
5 for e in lis:<br />
6 ret = e + ret<br />
7 return ret<br />
8 >>> summe(range(101))<br />
9 5050<br />
• Zweiter Parameter die Sequenz 10 >>> reduce(lambda x,y : x+y, range(101), 0)<br />
11 5050<br />
• Dritter Parameter der<br />
12 >>> fak = lambda x: reduce(lambda x,y: x*y,<br />
Anfangswert, meist neutral<br />
13 range(1, x+1), 1)<br />
• Ergebnis ist Auswertung der<br />
linksassoziativen sukkzesiven<br />
Funktionsanwendung<br />
14<br />
15<br />
16<br />
>>> fak(3)<br />
6<br />
>>> fak(6)<br />
17 720<br />
Beispiele: Summieren, Fakultät,<br />
18 >>> reduce(lambda x,y : x+" "+y,<br />
Stringkonkatenation<br />
19 ["Hallo", "tolle", "Welt"], "")<br />
20 ’ Hallo tolle Welt’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 193 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
reduce illustriert<br />
Initialer<br />
Wert<br />
0<br />
1 2 3<br />
4 5 6<br />
0 + 1<br />
1<br />
2 + 1<br />
3<br />
Kumulierte<br />
Werte<br />
3 + 3<br />
6 + 4<br />
6<br />
10<br />
10 + 5<br />
15<br />
15 + 6<br />
21<br />
lambda x, y: x+y<br />
1 >>> add = lambda x,y: x+y<br />
2 >>> reduce(add, [1, 2, 3, 4, 5, 6], 0)<br />
3 21<br />
4 >>> add(add(add(add(add(add(0, 1), 2), 3), 4), 5), 6) # foldl<br />
5 21<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 194 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Definition von map<br />
Primitive für funktionales <strong>Programmieren</strong><br />
1<br />
2<br />
def mymap(func, seq):<br />
ret = []<br />
• Können selbst implementiert werden<br />
3<br />
• Keine Schlüsselwörter, nur vordefiniert 4<br />
for ele in seq:<br />
ret.append(func(ele))<br />
mymap selbst gemacht<br />
5 return ret<br />
• for-Schleife<br />
• Funktion als Parameter<br />
• Aufbau der Ergebnisliste<br />
Verwenden wie eingebautes map<br />
• Implementierung mit mehreren<br />
Sequenzen auch einfach möglich<br />
• Gute Hausaufgabe<br />
1 >>> ink = lambda x: x+1<br />
2 >>> map(ink, [1, 2, 3])<br />
3 [2, 3, 4]<br />
4 >>> mymap(ink, [1, 2, 3])<br />
5 [2, 3, 4]<br />
6 >>> mymap(lambda x: x+1, [1, 2, 3])<br />
7 [2, 3, 4]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 195 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Definition von filter<br />
myfilter selbst gemacht<br />
• for-Schleife<br />
• Funktion als Parameter<br />
• Aufbau der Ergebnisliste<br />
Verwenden wie eingebautes filter<br />
1 def myfilter(func, seq):<br />
2 ret = []<br />
3 for ele in seq:<br />
4 if func(ele):<br />
5 ret.append(ele)<br />
6 return ret<br />
1 >>> filter(lambda x: x>10, range(20))<br />
2 [11, 12, 13, 14, 15, 16, 17, 18, 19]<br />
3 >>> filter(lambda x: x%2, range(20))<br />
4 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]<br />
5 >>> myfilter(lambda x: x>10, range(20))<br />
6 [11, 12, 13, 14, 15, 16, 17, 18, 19]<br />
7 >>> myfilter(lambda x: x%2, range(20))<br />
8 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]<br />
9 >>> myfilter(lambda x: x%2==0, range(20))<br />
10 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 196 / 326
<strong>Programmieren</strong> in Python<br />
Funktionale Primitive<br />
Definition von reduce<br />
myreduce selbst gemacht<br />
• for-Schleife<br />
• Funktion als Parameter<br />
• Aufbau des Ergebniswerts<br />
Verwenden wie eingebautes reduce<br />
1 def myreduce(func, seq, init=None):<br />
2 if init == None:<br />
3 init = seq[0]<br />
4 seq = seq[1:]<br />
5 wert = init<br />
6 for ele in seq:<br />
7 wert = func(wert, ele)<br />
8 return wert<br />
1 >>> add = lambda x,y: x+y<br />
2 >>> reduce(add, range(101))<br />
3 5050<br />
4 >>> myreduce(add, range(101))<br />
5 5050<br />
6 >>> sub = lambda x,y: x-y<br />
7 >>> myreduce(sub, [1,2,3,4,5], 100)<br />
8 85<br />
9 >>> reduce(sub, [1,2,3,4,5], 100)<br />
10 85<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 197 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
List Comprehension<br />
Listentransformation<br />
• Anwendungsgebiet wie funktionales<br />
<strong>Programmieren</strong><br />
• Einfachere Verwendung der<br />
Möglichkeiten von map und filter<br />
zusammen mit lambda und for<br />
Syntax [ for in ]<br />
• statt lambda-Ausdruck<br />
• Durch for wird sukkzesive ein<br />
Wert aus zugewiesen<br />
• Zusätzlich if , als Filter<br />
• Beliebig kombinierbar<br />
Ausdrucksweisen<br />
• Statt verschachtelte for-Schleifen<br />
• Ähnelt math. Mengenschreibweise<br />
1 >>> map(lambda x: x+1, [1,2,3,4])<br />
2 [2, 3, 4, 5]<br />
3 >>> [x+1 for x in [1,2,3,4]]<br />
4 [2, 3, 4, 5]<br />
5 >>> filter(lambda x:x>3, [1,5,2,6,7])<br />
6 [5, 6, 7]<br />
7 >>> [x for x in [1, 5, 2, 6, 7] if x>3]<br />
8 [5, 6, 7]<br />
1 >>> [x**2 for x in range(1, 11)<br />
2 if x % 2 == 0]<br />
3 [4, 16, 36, 64, 100]<br />
{x 2 |1 ≤ x ≤ 10, x mod 2 = 0} =<br />
{4, 16, 36, 64, 100}<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 198 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
List Comprehension – Beispiele mit Zahlen<br />
Quadratzahlen<br />
• Zahlen von 0 bis 9; 1 bis 10<br />
• Ausdruck statt Funktion<br />
Komplexe Definition<br />
• Mischen von Filtern und<br />
Funktionsapplikation<br />
• Aufzählen durch for<br />
Kartesisches Produkt<br />
• Sequenzen kombinieren<br />
• Kartesisches Produkt,<br />
Vollkombination<br />
• Nicht so bei funktionalem<br />
Primitiv map<br />
zip<br />
• Builtin, generiert Tupel<br />
1 >>> [x for x in range(10)]<br />
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]<br />
3 >>> [x*x for x in range(1, 11)]<br />
4 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
1 >>> [(x,y) for x in range(4)<br />
2 for y in range(0,5,2)<br />
3 if x < y]<br />
4 [(0, 2), (0, 4), (1, 2), (1, 4),<br />
5 (2, 4), (3, 4)]<br />
1 >>> map(lambda x,y: x+y, range(5), range(5))<br />
2 [0, 2, 4, 6, 8]<br />
3 >>> [x+y for x in range(5) for y in range(5)]<br />
4 [0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6,<br />
5 3, 4, 5, 6, 7, 4, 5, 6, 7, 8]<br />
1 >>> [x+y for (x,y) in zip(range(5),range(5))]<br />
2 [0, 2, 4, 6, 8]<br />
3 >>> zip(range(5), range(5))<br />
4 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 199 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
List Comprehension – Beispiele mit Text<br />
Wörter ersetzen<br />
• Kleine Zahlen durch Wörter ersetzen<br />
• Für alle Worte, falls das Wort 1,2 oder<br />
3 ist,<br />
• dann ersetze durch Zahlwort und<br />
setze neuen String zusammen<br />
Datei von Zahlen zeilenweise lesen<br />
• Zeilenweise einlesen und aufteilen<br />
(splitten)<br />
• Alle Strings aus Ziffern je Zeile in Liste<br />
von Zahlen umwandeln<br />
• Tupel aus Liste machen<br />
1 >>> trans = {’2’:’zwei’, ’3’: ’drei’,<br />
2 ’4’: ’vier’}<br />
3 >>> s = """2 Sachen und 3 Sachen sind<br />
4 nicht 4 Sachen"""<br />
5 >>> print " ".join([trans[w]<br />
6 if w in trans else w<br />
7 for w in s.split()])<br />
8 zwei Sachen und drei Sachen sind<br />
9 nicht vier Sachen<br />
1 >>> d = "zahlen.dat"<br />
2 >>> file(d).readlines()<br />
3 [’1 2 3\n’, ’42 343 12\n’,<br />
4 ’8 77 223\n’, ’23 43\n’,<br />
5 ’45 3 3 66 7\n’]<br />
6 >>> [tuple(map(int, line.split()))<br />
7 for line in file(d)]<br />
8 [(1, 2, 3), (42, 343, 12), (8, 77, 223),<br />
9 (23, 43), (45, 3, 3, 66, 7)]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 200 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Funktionale Programmierung – Zusammenfassung<br />
Vorteile<br />
• Verminderung der Fehleranfälligkeit, zum Beispiel sind viele Indexfehler gar nicht<br />
mehr formulierbar<br />
• Kompakter, ausdrucksstarker Code nahe an der Spezifikation<br />
• Gut zu lesen und zu verstehen, wenn nicht zu viel in einer Zeile passiert<br />
• Seiteneffektfrei, muss man natürlich auch darauf achten<br />
Nachteile<br />
• Syntax/Ausdrucksweise etwas gewöhnungsbedürftig<br />
• Funktionales Denken erfordert etwas Einarbeitungszeit<br />
Verbreitung<br />
• Funktionale Primitive in allen höheren Programmiersprachen zu finden (Ruby, Perl,<br />
Lisp, C#)<br />
• Lambda-Ausdrücke sind in C# für LINQ, in Java ab 8<br />
• MapReduce, Framework (Google) zum Suchen in riesigen Datenmenge<br />
Online-Referenzen<br />
• http://www-106.ibm.com/developerworks/linux/library/l-prog.html<br />
• http://www.freenetpages.co.uk/hp/alan.gauld/tutfctnl.htm<br />
• . . .<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 201 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Module<br />
Warum Module?<br />
• Wiederverwendung von Code<br />
• Bereitstellung von allgmein<br />
nutzbaren Diensten und<br />
Bibliotheken<br />
• Unterteilung des Namensraums<br />
bei großen Projekten<br />
Python Module<br />
• Jede Python-Datei (Endung mit<br />
.py) ist ein Modul<br />
• C-Erweiterungen sind Modul<br />
• Nutzen mit import, from<br />
Suche nach Dateien/Module<br />
• Umgebungsvariable PYTHONPATH<br />
• Abhängig von Wert in sys.path<br />
1 >>> import sys<br />
2 >>> sys.path<br />
3 [’’, # sucht auch im akt. Verzeichnis<br />
4 ’/usr/lib/python2.7’,<br />
5 ’/usr/lib/python2.7/plat-linux2’,<br />
6 ’/usr/lib/python2.7/lib-tk’,<br />
7 ’/usr/lib/python2.7/lib-old’,<br />
8 ’/usr/lib/python2.7/lib-dynload’,<br />
9 ’/usr/local/lib/python2.7/dist-packages’,<br />
10 ’/usr/lib/python2.7/dist-packages’,<br />
11 ’/usr/lib/python2.7/dist-packages/PIL’,<br />
12 ’/usr/lib/python2.7/dist-packages/gst-0.10’,<br />
13 ’/usr/lib/python2.7/dist-packages/gtk-2.0’,<br />
14 ’/usr/lib/pymodules/python2.7’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 202 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Definieren von Modulen<br />
Ein Modul ist eine Datei<br />
• Mit der Endung .py,<br />
oder vorkompiliert .pyc<br />
• In einem Verzeichnis<br />
• Beliebiger Python-Code<br />
• Keine Python-Schlüsselwörter als<br />
Dateiname<br />
Im Suchpfad erreichbar<br />
• Vorgabe ist aktuelles Verzeichnis und<br />
Standard-Bibliothek von Python<br />
• sys.path<br />
meinmodul.py<br />
1 # Modul meinmodul, meinmodul.py<br />
2 # Variablen und Funktionen<br />
3<br />
4 deutsch = "deutsch"<br />
5 englisch = "englisch"<br />
6<br />
7 sprache = deutsch<br />
8<br />
9 def drucke(x):<br />
10 print x<br />
11<br />
12 def gruss():<br />
13 if sprache == deutsch:<br />
14 drucke("Hallo Modul Welt")<br />
15 else:<br />
16 drucke("Hello module world")<br />
17<br />
18 print "meinmodul geladen"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 203 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Importieren von Modulen<br />
Modul importieren<br />
• Im aktuellen Verzeichnis<br />
• Wechseln mit os.chdir()<br />
• Importiert Modul mit dem<br />
Namen <br />
• Objekte nur über den<br />
Modul-Präfix erreichbar<br />
Namen von Modulen importieren<br />
• Modul selbst nicht sichtbar<br />
• Alle Namen im aktuellen<br />
Namensraum verfügbar<br />
• Aber an Objekt in Modul<br />
gebunden<br />
• * für alle Namen außer Namen,<br />
die mit einem Unterstrich _<br />
beginnen<br />
import [, ]*<br />
1 $ ls meinmodul.py<br />
2 meinmodul.py<br />
3 $ python<br />
4 >>> import meinmodul<br />
5 meinmodul geladen<br />
6 >>> meinmodul.gruss()<br />
7 Hallo Modul Welt<br />
8 >>> meinmodul.sprache=meinmodul.englisch<br />
9 >>> meinmodul.gruss()<br />
10 Hello module world<br />
11 >>> meinmodul.sprache = englisch<br />
12 NameError: name ’englisch’ is not defined<br />
from import [, ]*<br />
1 >>> from meinmodul import gruss<br />
2 >>> gruss()<br />
3 Hallo Modul Welt<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 204 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Module und Namensräume<br />
Ausführung beim Import<br />
• Modulanweisungen laufen nur beim<br />
ersten Import einmal ab<br />
• Achtung bei Entwicklung, IDLE<br />
restart führt neu aus, ohne restart<br />
werden Module nicht neu ausgeführt<br />
Modulattribute<br />
• Zuweisungen und<br />
10 {’drucke’: >> import meinmodul<br />
2 meinmodul geladen<br />
3 >>> dir(meinmodul)<br />
4 [’__builtins__’, ’__doc__’, ’__file__’,<br />
5 ’__name__’, ’__package__’, ’deutsch’,<br />
6 ’drucke’, ’englisch’, ’gruss’,<br />
7 ’sprache’]<br />
8 >>> import meinmodul<br />
9 >>> meinmodul.__dict__<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 205 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Hauptprogramm mit main<br />
Ziel<br />
• Ausführen eins Code-Blocks nur, wenn<br />
es als Hauptprogramm gestartet<br />
wurde; nicht wenn es importiert wurde<br />
• Simulieren der main-Funktion/Methode<br />
von C/Java<br />
• Häufig zum Testen eines Moduls<br />
verwendet<br />
Umsetzung, Idiom<br />
• Der Name des interaktiven oder<br />
Haupt-Moduls ist ’__main__’<br />
• Test auf Name und bedingt ausführen<br />
main.py<br />
1 import sys<br />
2<br />
3 def drucke(x):<br />
4 print "|%s|" % x<br />
5<br />
6 if __name__ == ’__main__’:<br />
7 print "drucker"<br />
8 for ele in sys.argv[1:]:<br />
9 drucke(ele)<br />
1 >>> import main<br />
2 >>> main.drucke("hallo")<br />
3 |hallo|<br />
4 >>> main.drucke("hello")<br />
5 |hello|<br />
$ python main.py hallo hello<br />
drucker<br />
|hallo|<br />
|hello|<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 206 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Qualifikation von Namen<br />
Einfacher Name<br />
• Auflösung über LEGB-Regel<br />
Qualifikation<br />
• .<br />
• Im Geltungsbereich des Moduls<br />
• Die gleiche Notation wie bei Objekten<br />
Qualifikationspfade<br />
• ..<br />
• Nur im genau spezifizierten<br />
Geltungsbereich<br />
Qualifikation funktioniert für alle Objekte:<br />
Module, Klassen, Typen, . . .<br />
qual.py<br />
1 import os<br />
2 name = "Name"<br />
1 >>> import qual<br />
2 >>> name<br />
3 NameError: name ’name’ is not defined<br />
4 >>> qual.name<br />
5 ’Name’<br />
6 >>> os.getcwd()<br />
7 NameError: name ’os’ is not defined<br />
8 >>> qual.os.getcwd()<br />
9 ’/home/mi/ssinn001/prog3’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 207 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Erzwingen von Neuladen<br />
Import von Modulen<br />
• Module werden beim ersten Import<br />
ausgeführt<br />
• Beim zweiten importieren wird nur ein<br />
neuer Namen wieder an das<br />
Modulobjekt gebunden<br />
• Zweiter Import sinnvoll um Modul im<br />
aktuellen Namensraum zu haben<br />
reload()<br />
• Lädt Modul neu, erstellt neues<br />
Modulobjekt<br />
• Wichtig beim Entwicklen, IDLE kein<br />
restart<br />
• Code-Änderungen werden erst dann<br />
wirksam<br />
m1.py<br />
1 import meinmodul<br />
m2.py<br />
1 import meinmodul<br />
m3.py<br />
1 import m1<br />
2 import m2<br />
3 print m1.meinmodul.gruss<br />
4 print m2.meinmodul.gruss<br />
5 m2.meinmodul = reload(m2.meinmodul)<br />
6 print m2.meinmodul.gruss<br />
1 $ python m3.py<br />
2 meinmodul geladen<br />
3 <br />
4 <br />
5 meinmodul geladen<br />
6 <br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 208 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Warum nicht from import *<br />
Verunreinigung des Namensraums<br />
• Namenskonflikte möglich<br />
• Gleiche Namen in Modulen würden im<br />
importierenden Modul überschreiben,<br />
der letzte gewinnt<br />
Importieren ist Namensbindung<br />
• Ist nicht immer was erwartet wird<br />
• Im Beispiel wird der Name sprache<br />
importiert<br />
• Die Funktion gruss verwendet natürlich<br />
noch sprache im Modul meinmodul<br />
from import * vermeiden<br />
Wenn Modulname zu lang, as<br />
1 >>> from meinmodul import *<br />
2 meinmodul geladen<br />
3 >>> gruss()<br />
4 Hallo Modul Welt<br />
5 >>> sprache = "englisch"<br />
6 >>> gruss()<br />
7 Hallo Modul Welt<br />
8 >>> import meinmodul<br />
9 >>> meinmodul.sprache = "englisch"<br />
10 >>> gruss()<br />
11 Hello module world<br />
import as <br />
1 >>> import meinmodul as mm<br />
2 meinmodul geladen<br />
3 >>> mm.gruss()<br />
4 Hallo Modul Welt<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 209 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Warum nicht from import *<br />
1 >>> from meinmodul import *<br />
2 meinmodul geladen<br />
3 >>> gruss()<br />
4 Hallo Modul Welt<br />
5 >>> sprache = "englisch"<br />
6 >>> gruss()<br />
7 Hallo Modul Welt<br />
8 >>> import meinmodul<br />
9 >>> meinmodul.sprache = "englisch"<br />
0 >>> gruss()<br />
1 Hello module world<br />
import as <br />
1 >>> import meinmodul as mm<br />
2 meinmodul geladen<br />
3 >>> mm.gruss()<br />
4 Hallo Modul Welt<br />
__main__<br />
deutsch<br />
englisch<br />
sprache<br />
drucke<br />
gruss<br />
meinmodul<br />
deutsch<br />
englisch<br />
sprache<br />
drucke<br />
gruss<br />
__main__<br />
meinmodul<br />
mm<br />
“deutsch“<br />
“englisch“<br />
lambda...<br />
lambda...<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 210 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Datenkapselung und Daten verstecken<br />
meinmodul.py (Erweiterung)<br />
Datenkapselung<br />
1 #...<br />
• Kapselung ist Ziel von Modulen<br />
2 def andere_sprache(s):<br />
3<br />
•<br />
global sprache<br />
Nicht erzwungen in Python, kein<br />
4 if s in [deutsch, englisch]:<br />
public, private, protected<br />
5 sprache = s<br />
• Nur “unhöflich”, gegen Konvention<br />
6 else:<br />
Daten verstecken<br />
7 raise Exception("Sprache %s" % s)<br />
• Konvention mit _<br />
•<br />
1<br />
Durchgriff möglich<br />
>>> import meinmodulgross as mm<br />
2 >>> mm.gruss()<br />
• Nicht importiert bei *<br />
3 Hallo Modul Welt<br />
Konventionen<br />
4 >>> mm.andere_sprache(mm.englisch)<br />
5<br />
• Keine Modulattribute ändern, nur lesen >>> mm.gruss()<br />
6 Hello module world<br />
• Nur Funktionen verwenden<br />
7 >>> mm.andere_sprache("portugiesisch")<br />
• Keine Funktionen mit _ am Anfang 8 Exception: Sprache portugiesisch<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 211 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Pakete/Packages – Ordner als Module<br />
Flache Struktur<br />
• Viele Module flach im Ordner ok<br />
• In großem Projekt nicht ausreichend<br />
• Standardbibliotheken so nicht gut<br />
strukturierbar<br />
• Besser Hierarchie von Ordnern<br />
Package<br />
• Ordner als Hierachiestufen bei der<br />
Namensqualifikation (wie Java)<br />
• Wenn ein Ordner die Datei<br />
__init__.py enthält, dann ist der<br />
Ordner ein Package<br />
• __init__.py kann Initialisierungscode<br />
der Package enthalten, zum Beispiel<br />
Module nachladen und Namensraum<br />
ausgestalten<br />
paket/a.py<br />
1 s = "hallo"<br />
2 def machgross(s):<br />
3 return s.upper()<br />
paket/b.py<br />
1 import string<br />
2 def machklein(s):<br />
3 return s.lower()<br />
paket/__init__.py<br />
1 import a<br />
2 from a import s<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 212 / 326
<strong>Programmieren</strong> in Python<br />
List Comprehension<br />
Pakete/Packages – Beispiel Verwendung<br />
paket/a.py<br />
1 >>> import paket<br />
1 s = "hallo"<br />
2 >>> paket.a<br />
2 def machgross(s):<br />
3 <br />
3 return s.upper()<br />
4 >>> paket.a.machgross("ab")<br />
5 ’AB’<br />
paket/b.py<br />
6 >>> paket.a.s, paket.s<br />
1 import string<br />
7 (’hallo’, ’hallo’)<br />
2 def machklein(s):<br />
8 >>> paket.b<br />
3 return s.lower()<br />
9 AttributeError: ’module’ object has<br />
10 no attribute ’b’<br />
paket/__init__.py<br />
11 >>> import paket.b<br />
12 >>> paket.b<br />
1 import a<br />
13 <br />
2 from a import s<br />
14 >>> paket.b.string.lower("hallo")<br />
15 ’hallo’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 213 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Objektorientierung in Python<br />
Ähnlich zu Java<br />
• Schlüsselworte, Referenzsemantik<br />
• Attribute, Vererbung, Polymorphismus<br />
• Einfach, Sprache mit OO konzipiert<br />
Unterschiede, neue Features<br />
• Dynamische Attribute, Attributsuche<br />
• Mehrfachvererbung, keine Schnittstellen<br />
• Kapselung (Komposition) nur per Konvention,<br />
aber Properties<br />
• Operatorenüberladung, Duck-Typing (reagieren auf<br />
Index-Zugriff, Ausgabe, Slicen)<br />
• Selbst erstellte Klassen verhalten sich wie<br />
eingebaute Typen<br />
• Alles! ist ein Objekt (Zahlen, Module, . . . )<br />
1 >>> i=3<br />
2 >>> type(i)<br />
3 <br />
4 >>> isinstance(i, int)<br />
5 True<br />
6 >>> i.__add__<br />
7 <br />
9 >>> i.__add__(4)<br />
10 7<br />
11 >>> i.__mul__(4)<br />
12 12<br />
13 >>> object<br />
14 <br />
15 >>> issubclass(int, object)<br />
16 True<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 214 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassen<br />
Klassendefinition<br />
• class: Schlüsselwort<br />
• : Name für die Klasse<br />
• object: Wurzelklasse, immer angeben<br />
• : Dokumentationsstring<br />
• : Funktionsdefinitionen für Methoden<br />
Besonderheiten<br />
• Erstes Methodenargument ist immer Instanzobjekt<br />
• Per Konvention der Name self, in Java wäre es this<br />
• Spezielle Methode __init__ statt Konstruktor<br />
• Attribute sind Klassenattribute und nicht, wie von<br />
Java erwartet, Instanzattribute<br />
• Instanzattribute dynamisch (__init__) in<br />
Namensraum self schreiben<br />
class (object):<br />
[]<br />
<br />
klasse.py<br />
1 class A(object):<br />
2 "Eine Klasse A"<br />
3 def __init__(self):<br />
4 self.a = 17<br />
5 def inca(self):<br />
6 self.a += 1<br />
7 print A<br />
$ python klasse.py<br />
<br />
Ausführung erzeugt<br />
Klassenobjekt (Klassen<br />
sind Objekte!), binden<br />
Klassenname an<br />
Klassenobjekt<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 215 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassendefinition – Beispiel Stack<br />
Stack auf Basis von Listen (Komposition)<br />
• Initialisierung der Instanzvariable<br />
liste mit leere Liste<br />
• self ist immer das erste Argument bei<br />
Methoden<br />
• self muss explizit aufgeführt werden<br />
bei der Definition<br />
• self ist Namensraum einer Instanz<br />
• Weitere Argumente bei Methoden<br />
erlaubt<br />
• Manipulation der Instanzattribute in<br />
self sollte nur durch Methoden<br />
erfolgen<br />
• Keine get/set Methoden schreiben!<br />
• Später mit Properties<br />
1 class Stack(object):<br />
2 "Stack-Klasse mit Python Listen"<br />
3<br />
4 def __init__(self):<br />
5 self.liste = []<br />
6<br />
7 def push(self, elem):<br />
8 self.liste.append(elem)<br />
9<br />
10 def pop(self):<br />
11 del self.liste[-1]<br />
12<br />
13 def top(self):<br />
14 return self.liste[-1]<br />
15<br />
16 def clear(self):<br />
17 self.liste = []<br />
18<br />
19 def empty(self):<br />
20 return self.liste == []<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 216 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Generieren und Nutzen von Instanzen<br />
Klassendefinition<br />
• Klassenname ist Name gebunden an<br />
Klassenobjekt<br />
• Im Beispiel Stack in stack.py<br />
Instanziierung<br />
• Neue Instanz durch Aufruf<br />
Klassennamen (kein new)<br />
• Implizit wird __init__ aufgerufen<br />
• Zuweisung der Instanz an Namen<br />
• Name referenziert dann Instanzobjekt<br />
Nutzen wie gewohnt<br />
• Kapselung nicht erzwungen aber<br />
Konvention<br />
>>> from stack import Stack<br />
>>> Stack<br />
<br />
>>> s = Stack()<br />
<br />
>>> s.empty()<br />
True<br />
>>> s.push(1); s.push(2); s.push(3)<br />
>>> s.liste # Boese, nicht machen<br />
[1, 2, 3]<br />
>>> s.empty()<br />
False<br />
>>> s.top()<br />
3<br />
>>> s.pop()<br />
>>> s.top()<br />
2<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 217 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Vererbung und Mehrfachvererbung<br />
Vererbung<br />
• Superklassen in Klammern dahinter<br />
• object nur dann nicht mehr notwendig<br />
1<br />
class ( [, ]*):<br />
...<br />
fancystack.py<br />
from stack import Stack<br />
• Ganz ohne Superklassen werden es<br />
2<br />
Old-Style Klassen, deprecated<br />
3 class FancyStack(Stack):<br />
• Mehrfachvererbung möglich<br />
Mehrfachvererbung<br />
4<br />
5<br />
def peek(self, i):<br />
return self.liste[i]<br />
• Suche nach Attribut oder<br />
Methodenname<br />
• Erst in aktueller Klasse<br />
• Dann in Superklassen wie definiert<br />
• Erst alle Superklassen der<br />
Superklassen<br />
• Kurz: von links nach rechts,<br />
Tiefensuche*<br />
9 1<br />
*In der Realität etwas komplizierter<br />
http://www.python.org/download/releases/2.3/mro/<br />
1 >>> from fancystack import FancyStack<br />
2 >>> s = FancyStack()<br />
3 >>> s<br />
4 >> s.push(1); s.push(2); s.push(3)<br />
6 >>> s.peek(2)<br />
7 3<br />
8 >>> s.peek(0)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 218 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassen- und Instanzvariablen<br />
Instanzvariablen<br />
• Zuweisung an durch self<br />
aufgespannten Namensraum<br />
•<br />
5<br />
Unabhängig von allen anderen Namen def show_verbose(self):<br />
6 print "Klasse", K.verbose<br />
• Entspricht Instanzvariablen in Java<br />
7 print "Instanz", self.verbose<br />
Klassenvariablen<br />
• Initialisierung als Attribute<br />
• In durch Klassennamen<br />
aufgespannten Namensraum<br />
• Entspricht static Variablen in Java<br />
• Achtung: Syntax wie Instanzvariablen<br />
in Java<br />
1 class K(object):<br />
2 verbose = 1<br />
3 def __init__(self, v):<br />
4 self.verbose = v<br />
1 >>> K.verbose<br />
2 1<br />
3 >>> i = K(2)<br />
4 >>> i.verbose<br />
5 2<br />
6 >>> K.verbose<br />
7 1<br />
8 >>> i.show_verbose()<br />
9 Klasse 1<br />
10 Instanz 2<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 219 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassen- und Instanzvariablen – Attributsuche<br />
Suchordnung<br />
• Erst Instanz, dann Klasse, dann<br />
Superklassen<br />
Suche in self<br />
• Wenn keine Instanzvariable vorliegt,<br />
wird die der Klasse gelesen,<br />
Zeile 2<br />
Zur Laufzeit änderbar<br />
• Instanzvariable zur Laufzeit<br />
hinzufügbar, Zeile 4<br />
Klassenvariable nur noch qualifiziert<br />
• Zugriff über Namensraum der Klasse,<br />
Zeile 7<br />
1 class K(object):<br />
2 verbose = 1<br />
3 def __init__(self):<br />
4 pass<br />
1 >>> k = K()<br />
2 >>> k.verbose<br />
3 1<br />
4 >>> k.verbose = 2<br />
5 >>> k.verbose<br />
6 2<br />
7 >>> K.verbose<br />
8 1<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 220 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassenmethoden<br />
Statische Methoden<br />
• Klassenmethode, bezieht sich nicht<br />
auf Instanz, in Java static<br />
• Syntax: Dekorator @staticmethod<br />
• Kein erstes Argument self mehr<br />
vorhanden<br />
Klassenmethode<br />
• Klassenmethode, wobei das erste<br />
Argument die Klasse ist<br />
• Syntax: Dekorator @classmethod<br />
• Überschreiben möglich,<br />
fortgeschrittenes Konzept, vermeiden<br />
1 class K(object):<br />
2 zaehle = 1<br />
3 def __init__(self):<br />
4 self.zahl = 17<br />
5 @staticmethod<br />
6 def statisch(x):<br />
7 K.zaehle += x<br />
8 @classmethod<br />
9 def klassenmethode(cls, x):<br />
10 cls.zaehle += x<br />
1 >>> k = K()<br />
2 >>> k.zaehle, K.zaehle<br />
3 (1, 1)<br />
4 >>> k.statisch(3)<br />
5 >>> K.zaehle<br />
6 4<br />
7 >>> k.klassenmethode(3)<br />
8 >>> K.zaehle<br />
9 7<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 221 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Dekorator<br />
Dekoratorfunktion<br />
• Funktion, die mindestens eine<br />
Funktion als Argument hat und eine<br />
Funktion zurückgibt; einpacken<br />
• Ziel: Verhalten und Syntax einer<br />
Funktion ändern<br />
• Beispieleinsatz: statische Methoden<br />
• Beispiel: statisch in Zeilen 6-8, in<br />
Python
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Alternative zu Klassenmethoden<br />
1 _kzaehle=1 # nicht importieren bei<br />
Klassenscope meist nicht notwendig<br />
*<br />
2 def statisch(x):<br />
• In Java kein umfassende<br />
3 global _kzaehle<br />
Modulkonzept vorhanden, keine Werte 4 _kzaehle += x<br />
auf globaler Ebene<br />
5 class K(object):<br />
6<br />
• Statische Methoden und<br />
def __init__(self):<br />
7 self.zahl = 17<br />
Klassenvariablen um zu kompensieren<br />
• In Python Kompensation nicht<br />
notwendig<br />
Nutzen Modulkonzept<br />
1 def statisch(x):<br />
2 K.zaehle += x<br />
3 class K(object):<br />
• Statt Klassenvariable Modulvariable<br />
4 zaehle = 1<br />
5 def __init__(self):<br />
• Statt statische Methode Modulfunktion<br />
6 self.zahl = 17<br />
• Häufig passender<br />
1 >>> k = K()<br />
2 >>> statisch(3)<br />
3 >>> K.zaehle<br />
4 4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 223 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassen und Instanzen sind Namensräume<br />
Nicht qualifizierte Namen nach<br />
Geltungsbereichen<br />
• x=wert; weist an lokalen Namen zu<br />
• x; Zugriff mit LEGB-Regel<br />
Qualifizierte Namen<br />
• Namensraum des Objekts<br />
1 x = 4<br />
2 class K1(object):<br />
3 def __init__(self):<br />
4 self.x = 1<br />
5 class K2(K1):<br />
6 x = 3<br />
7 def __init__(self):<br />
8 K1.__init__(self)<br />
9<br />
• def f(self):<br />
Suche erst in aktueller Instanz,<br />
10 self.x = 2<br />
beinhaltet was durch Superklassen an<br />
11 def showx(self):<br />
Instanz geändert wurde,<br />
12 print self.x,<br />
dann erst in Klassenscope<br />
13 k = K2(); k.showx()<br />
• Nicht im definierenden Modul<br />
14 k.f(); k.showx()<br />
15 del k.x; k.showx()<br />
16 del K2.x; k.showx()<br />
1 1 2 3<br />
2 AttributeError: ’K2’ object<br />
3 has no attribute ’x’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 224 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Klassen, Selbstbeobachtung<br />
Umsetzung, Interna<br />
• Attribute mit doppelten Unterstrichen<br />
• Direkter Zugriff nur wenn notwendig<br />
Klassen<br />
• Name, Superklassen<br />
Instanzen<br />
• Klasse der Instanz<br />
• Namensraum mit __dict__<br />
• Realisiert mit Dictionaries<br />
Selbst ausprobieren!<br />
1 class K(object):<br />
2 verbose = 1<br />
3 def __init__(self): pass<br />
1 >>> from klasse import K<br />
2 >>> K.__name__ # der Name<br />
3 ’K’<br />
4 >>> K.__bases__ # die Superklassen<br />
5 (,)<br />
6 >>> k = K()<br />
7 >>> k.__class__, k.__dict__<br />
8 (, {})<br />
9 >>> dir(k)<br />
10 [’__class__’, ’__delattr__’, ’__dict__’,<br />
11 ’__doc__’, ’__format__’, ’__getattribute_<br />
12 ’__hash__’, ’__init__’, ’__module__’,<br />
13 ’__new__’, ’__reduce__’, ’__reduce_ex__’,<br />
14 ’__repr__’, ’__setattr__’, ’__sizeof__’,<br />
15 ’__str__’, ’__subclasshook__’, ’__weakref<br />
16 ’verbose’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 225 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Properties statt Getter und Setter<br />
Durchgriff auf Attribute<br />
• Ist in Python in Ordnung<br />
• Keine Getter und Setter<br />
• Man kann nachträglich ändern und<br />
Kontrolle wieder erlangen<br />
Properties<br />
• Eigentliches Attribut verstecken, _ am<br />
Namensanfang als Hinweis<br />
• Definition Getter, Setter und Löschen<br />
• Definition des Attributs mit<br />
property(get, set, delete, doc)<br />
1 class Name(object):<br />
2<br />
3 def __init__(self):<br />
4 self._vorname = "Max"<br />
5<br />
6 def get_vorname(self):<br />
7 return self._vorname<br />
8<br />
9 def set_vorname(self, value):<br />
10 oktypes = [str, unicode]:<br />
11 if type(value) not in oktypes:<br />
12 msg = "vorname kein String"<br />
13 raise AttributeError(msg)<br />
14 self._vorname = value<br />
15<br />
16 vorname = property(get_vorname,<br />
17 set_vorname,<br />
18 None,<br />
19 "Vorname als String/Unicode")<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 226 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Properties verwenden<br />
Auf Klassenebene zugewiesenes Attribut<br />
wie Instanzvariable verwenden<br />
• Automatisch Aufruf der passenden<br />
Methode<br />
• Wenn nicht angegeben, dann<br />
Verwendung nicht möglich<br />
Durchgriff: Immer noch möglich, nicht<br />
machen<br />
1 >>> name = Name()<br />
2 >>> name.vorname<br />
3 ’Max’<br />
4 >>> name.vorname = ’Susi’<br />
5 >>> name.vorname<br />
6 ’Susi’<br />
7 >>> name.vorname = 17<br />
8 AttributeError: vorname kein String<br />
9 >>> name.vorname<br />
10 ’Max’<br />
11 >>> del name.vorname<br />
12 AttributeError: can’t delete attribute<br />
13 >>> name.vorname<br />
14 ’Max’<br />
15<br />
16 >>> n._vorname = 17<br />
17 >>> n.vorname<br />
18 17<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 227 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Überladen von Operatoren – Motivation<br />
Ziel<br />
• Rechnen Modulo einer Zahl mod<br />
• Alle Ergebnisse sollen zwischen 0 und<br />
mod-1 liegen<br />
Lösung<br />
• Klasse Modulo<br />
• Initialisiert mit Wert mod<br />
• Implementierung der Operationen<br />
durch Standardoperationen, aber<br />
Anpassung modulo<br />
• Funktioniert, Benutzung nicht intuitiv<br />
Wunsch<br />
• Benutzen der Modulo-Instanzen wie<br />
eingebaute Zahlen<br />
1 class Modulo(object):<br />
2 "Rechnen modulo einer Zahl"<br />
3 def __init__(self, mod, zahl=0):<br />
4 self.mod = mod<br />
5 self.zahl = zahl<br />
6 def wert(self):<br />
7 return self.zahl<br />
8 def add(self, z):<br />
9 zahl, mod = self.zahl, self.mod<br />
10 self.zahl = (zahl+z) % mod<br />
1 >>> m = Modulo(7)<br />
2 >>> m.wert()<br />
3 0<br />
4 >>> m.add(4); m.wert()<br />
5 4<br />
6 >>> m.add(5); m.wert()<br />
7 2<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 228 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Überladen von Operatoren – Umsetzung<br />
Vordefinierte Funktionsnamen<br />
• Werden gerufen bei Anwendung von<br />
Operatoren<br />
• Beginnen und enden mit zwei<br />
Unterstrichen<br />
• Definition neuer Operatoren nicht<br />
möglich<br />
Beispiele<br />
• __repr__: Repräsentation bei<br />
interaktiver Ausgabe, es wird String<br />
erwartet, Java’s toString ist __str__<br />
• __add__: Wird gerufen bei<br />
linksseitigem + Operator<br />
Achtung: Eingebautes + liefert immer<br />
ein neues Objekt, auch so machen<br />
1 ...<br />
2 def __repr__(self):<br />
3 return str(self.zahl)<br />
4 __str__ = __repr__<br />
5 def __add__(self, z):<br />
6 n = Modulo(self.mod, self.zahl)<br />
7 n.add(z)<br />
8 return n<br />
1 >>> m = Modulo(7)<br />
2 >>> m<br />
3 0<br />
4 >>> m.add(4)<br />
5 >>> m<br />
6 4<br />
7 >>> m+5<br />
8 2<br />
9 >>> m<br />
10 4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 229 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Überladbare Operatoren – Auszug<br />
• __init__: Konstruktorersatz, __init__ der Superklasse nicht automatisch gerufen<br />
• __del__: Destruktorersatz, beim expliziten Löschen und bei Garbage-Collection<br />
• __add__, __or__: Operator +, |<br />
• __repr__: Drucken (print), Konvertierung<br />
• __call__: Funktionsaufruf ()<br />
• __getattr__, __getattribute__: Qualifikation<br />
• __getitem__: Indizierung, auch von in-Operator verwendet<br />
• __setitem__: Zuweisung über Index<br />
• __getslice__: Teilbereichsbildung<br />
• __len__: Länge<br />
• __cmp__: Vergleich<br />
• __eq__, __ne__: Gleichheit (==), Ungleichheit(!=)<br />
• __radd__: Rechtsseitiger Operator +<br />
Details und weitere Operatoren in der Dokumentation<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 230 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Von eingebauten Klassen ableiten<br />
Beispiel eigenes Wörterbuch<br />
• Verhalten wie dict, aber nur Strings<br />
als Schlüssel<br />
• Alles andere gleich<br />
Umsetzung<br />
• Von dict ableiten, Vererben alternativ<br />
zu Komposition<br />
• Überladen von __setitem__<br />
• Nutzen von __setitem__ der<br />
Superklasse (Achtung: sonst<br />
unendliche Rekursion)<br />
1 class strdict(dict):<br />
2 def __setitem__(self, key, value):<br />
3 if type(key) != str:<br />
4 msg = "nur String als Key"<br />
5 raise AttributeError(msg)<br />
6 dict.__setitem__(self, key, value)<br />
1 >>> dic = dict()<br />
2 >>> dic[1] = 2<br />
3 >>> dic["eins"] = 2<br />
4 >>> dic<br />
5 {1: 2, ’eins’: 2}<br />
6 >>> strdic = strdict()<br />
7 >>> strdic[1] = 2<br />
8 AttributeError: nur String als Key<br />
9 >>> strdic["eins"] = 2<br />
10 >>> strdic<br />
11 {’eins’: 2}<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 231 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Iteratoren für eigene Klassen<br />
for-Kontrollstruktur<br />
• Einfaches Iterieren über Sequenzen<br />
• Funktioniert mit Iterator-Objekt<br />
• next gibt nächstes Element zurück<br />
• Ausname StopIteration, wenn kein<br />
Element mehr verfügbar<br />
• Ähnlich zu Java<br />
iter-Methode, eingebaut<br />
3<br />
• Holt von Objekt Iterator, wenn möglich<br />
>>> it<br />
4 <br />
• Implizit und explizit verwendbar<br />
5 >>> it.next()<br />
• Beispiel mit Listen<br />
1 >>> l = [1, 2, 3]<br />
2 >>> lis = [1, 2, 3]<br />
3 >>> for ele in lis:<br />
4 print ele<br />
5 1<br />
6 2<br />
7 3<br />
1 >> lis = [1, 2, 3]<br />
2 >>> it = iter(l)<br />
6 1<br />
7 >>> it.next()<br />
8 2<br />
9 >>> it.next()<br />
10 3<br />
11 >>> it.next()<br />
12 StopIteration<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 232 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Iteratoren für eigene Klassen – Instanz selbst<br />
Selbst implementieren in der Klasse<br />
• Überladen von __iter__<br />
• Erwartet Iterator-Objekt<br />
Bewertung<br />
• Zum Beispiel sich selbst, wenn<br />
Methode next definiert ist<br />
• Keine Schnittstellen, Duck-Typing<br />
• Einfach zu realisieren<br />
1 class Iterselbst(object):<br />
2 def __init__(self):<br />
3 self.lis = [1,2,3]<br />
4 def __iter__(self):<br />
5 self.index = 0<br />
6 return self<br />
7 def next(self):<br />
8 if self.index >= len(self.lis):<br />
9 raise StopIteration<br />
10 self.index += 1<br />
11<br />
• return self.lis[self.index-1]<br />
Nachteil: Nur ein Iterator gleichzeitig je<br />
Instanz, da aktueller Zustand nur<br />
1 >>> its = Iterselbst()<br />
einmal in der Instanz gespeichert ist<br />
2 >>> for ele in its:<br />
3 print ele,<br />
4 1 2 3<br />
5 >>> its = Iterselbst()<br />
6 >>> it1, it2 = iter(its), iter(its)<br />
7 >>> it1.next(), it2.next()<br />
8 (1, 2)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 233 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Iteratoren für eigene Klassen – Iterator-Klasse<br />
Separate Iterator-Klasse<br />
• Neu definierte Iterator-Klasse itk<br />
• Kann durchaus im normalen<br />
Codeblock dynamisch erfolgen<br />
• Instanz der Klasse initialisieren und<br />
zurückgeben<br />
Bewertung<br />
• Etwas komplexer zu realisieren<br />
• Erlaubt parallele Iteration<br />
• Ändern des Objekts während der<br />
Iteration erlaubt, da Kopie erstellt<br />
wurde<br />
• Kopie erstellen bewusste<br />
Entscheidung<br />
1 class Iterklasse(object):<br />
2 def __init__(self):<br />
3 self.lis = [1,2,3]<br />
4 def __iter__(self):<br />
5 class itk(object):<br />
6 def __init__(self, lis):<br />
7 self.index = 0<br />
8 self.lis = lis[:]<br />
9 def next(self):<br />
10 if self.index >= len(self.lis):<br />
11 raise StopIteration<br />
12 self.index += 1<br />
13 return self.lis[self.index-1]<br />
14 return itk(self.lis)<br />
1 >>> itc = Iterklasse()<br />
2 >>> it1, it2 = iter(itc), iter(itc)<br />
3 >>> it1.next(), it2.next()<br />
4 (1, 1)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 234 / 326
<strong>Programmieren</strong> in Python<br />
Objektorientierung<br />
Iteratoren für eigene Klassen – Iterator von Standardtyp<br />
Iterator von Standardtyp verwenden<br />
• Standardtyp nehmen oder aufbauen<br />
• Davon Iterator zurückgeben<br />
Bewertung<br />
• Einfach, robust; bevorzugen<br />
in Tests<br />
• Sobald Iterator implementiert ist, ist<br />
auch automatisch der in-Operator<br />
realisiert<br />
• Iteriert über alle Element und<br />
vergleicht<br />
• Bessere Implementierung darf man<br />
angeben<br />
1 class Iterstd(object):<br />
2 def __init__(self):<br />
3 self.lis = [1, 2, 3]<br />
4 def __iter__(self):<br />
5 return iter(self.lis)<br />
1 >>> its = Iterstd()<br />
2 >>> it1, it2 = iter(its), iter(its)<br />
3 >>> it1.next(), it2.next()<br />
4 (1, 1)<br />
1 >>> its = Iterstd()<br />
2 >>> 3 in its, 17 in its<br />
3 (True, False)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 235 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Motivation<br />
Iteratoren – Umsetzungskonzept<br />
• Iterator: Zwischen jedem next<br />
Anwendungscode ausführen<br />
• Iteratorklasse: Zustand halten und bei<br />
jedem next aktualisieren<br />
• Statt Iteratorklasse?: Einfache Schleife<br />
klappt nicht; man kann Ausführung<br />
nicht anhalten und Anwendungscode<br />
ausführen<br />
Lösungsansätze<br />
• Man kann den Anwendungscode, den<br />
man für jedes Objekt ausführen will<br />
“mitgeben”: Funktionales<br />
<strong>Programmieren</strong><br />
• Man kann die Schleife doch anhalten;<br />
Generatoren<br />
1 i = 0<br />
2 def naechstes():<br />
3 global i<br />
4 if i >= len(lis):<br />
5 raise StopIteration<br />
6 ele = lis[i]<br />
7 i += 1<br />
8 return ele<br />
1 for ele in lis:<br />
2 # naechstes ele, Anwendungscode?<br />
3 pass<br />
1 def f(x):<br />
2 pass # Anwendungscode<br />
3 ###<br />
4 map(f, lis)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 236 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Konzept<br />
Generatoren in Python<br />
• yield statt return in Funktion<br />
• Nur eins von beiden in Funktion<br />
• Bei Funktionsaufruf wird automatisch<br />
Generatorobjekt erzeugt, das sich wie<br />
Iterator verhält<br />
• Bei next wird Wert bei yield<br />
zurückgegeben und Ausführung<br />
eingefroren<br />
• Bei jedem next zum nächsten Wert<br />
• StopIteration am Ende<br />
Vorteile<br />
• Keine großen Datenstrukturen im<br />
Speicher halten<br />
• Natürliche Realisierung von Iteratoren<br />
• Grundlage für die meisten Builtins<br />
quads.py<br />
1 def quads():<br />
2 i = 1<br />
3 while True:<br />
4 yield i**2<br />
5 i += 1<br />
1 >>> q = quads()<br />
2 >>> q.next()<br />
3 1<br />
4 >>> q.next()<br />
5 4<br />
6 >>> q.next()<br />
7 9<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 237 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Grundlage für viele Builtins<br />
Beispiel: Eine offene Datei ist ein<br />
Generator, der die Zeilen in der Datei<br />
sukkzesive zurückgibt<br />
1 >>> f = file("quads.py"); f<br />
2 <br />
4 >>> f.next()<br />
5 ’def quads():\n’<br />
6 >>> f.next()<br />
7 ’ i = 1\n’<br />
8 ....<br />
9 >>> f.next()<br />
0 ’ i += 1\n’<br />
1 >>> f.next()<br />
2 StopIteration<br />
Beispiel: Das Ergebnis eines Aufrufs von<br />
reversed ist ein Generator, der die<br />
Elemente rückwärts aufzählt<br />
1 >>> lis = [1, 2, 3]<br />
2 >>> g = reversed(lis); g<br />
3 <br />
5 >>> g.next()<br />
6 3<br />
7 >>> g.next()<br />
8 2<br />
9 >>> g.next()<br />
10 1<br />
11 >>> g.next()<br />
12 StopIteration<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 238 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Verwendung und weitere Beispiele<br />
Verwendung<br />
• Summe der Quadratzahlen, die zum<br />
ersten Mal 1.000.000 erreicht<br />
nquads<br />
• quads war unendlich, beschränkt geht<br />
auch<br />
• Mit list wird wieder eine Liste daraus,<br />
läuft ewig für unendliche Generatoren<br />
• Verwendung von for möglich und<br />
sinnvoll auch bei potentiell unendlich<br />
lange laufenden Generatoren<br />
• Abbruch mit StopIteration<br />
• Abbruch nicht notwendig<br />
1 def hoch4():<br />
2 for ele in quads():<br />
3 yield ele**2<br />
1 sum = 0<br />
2 for quad in quads():<br />
3 sum += quad<br />
4 if sum > 1000000:<br />
5 break<br />
6 print sum # 1005720<br />
1 def nquads(n):<br />
2 for i in range(1, n+1):<br />
3 yield i**2<br />
1 def nquads(n):<br />
2 grenze = n**2<br />
3 for ele in quads():<br />
4 yield ele<br />
5 if ele >= grenze:<br />
6 raise StopIteration<br />
>>> list(nquads(10))<br />
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 239 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Fibonacci<br />
Folge der Fibonacci-Zahlen<br />
• Startwerte, zwei Mal die Eins<br />
• Die nächste Fibonacci-Zahl ist die<br />
Summe der beiden Vorherigen<br />
Umsetzung<br />
• Aktuelle und vorletzte Fibonacci-Zahl<br />
halten<br />
• Vorletzte zurück geben und dabei<br />
Zustand einfrieren<br />
Verwendung<br />
• Die ersten 10 Fibonacci-Zahlen<br />
1 def fib():<br />
2 fn0, fn1 = 1, 1<br />
3 while True:<br />
4 fn0, fn1, fn2 = fn0+fn1, fn0, fn1<br />
5 yield fn2<br />
1 >>> f = fib()<br />
2 >>> for i in range(10):<br />
3 print f.next(),<br />
4 1 1 2 3 5 8 13 21 34 55<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 240 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Baum traversieren<br />
Baum<br />
• Knoten als Drei-Tupel, Wert ist String<br />
• Iterator für In-Order normalerweise<br />
aufwendig, Warteschlange<br />
Baum traversieren mit Generatoren<br />
• Natürliche Formulierung<br />
• Nutzen von Schleifen mit neuen<br />
Generatoren im rekursiven Abstieg<br />
bintree<br />
b<br />
a<br />
c<br />
1 def inorder(node):<br />
2 if node == None:<br />
3 raise StopIteration<br />
4 left, value, right = node<br />
5 for valueleft in inorder(left):<br />
6 yield valueleft<br />
7 yield value<br />
8 for valueright in inorder(right):<br />
9 yield valueright<br />
1 bintree = (<br />
2 ((None, "d", None),<br />
3 "b",<br />
4 (None, "e", None)),<br />
5 "a",<br />
6 (None, "c", None))<br />
d<br />
e<br />
1 >>> for value in inorder(bintree):<br />
2 print value,<br />
3 d b e a c<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 241 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – itertools, Slicen<br />
Generatoren sind keine Sequenzen<br />
• Generatoren sind potentiell unendlich<br />
• Umformung in Listen und Slicing nicht<br />
sinnvoll<br />
• Standard-Features von Sequenzen<br />
(Slicing, Syntax) nicht verfügbar<br />
Modul itertools<br />
• Wichtigste Funktionalität von<br />
Sequenzen für Generatoren zur<br />
Verfügung stellen<br />
• Slicen, Funktional <strong>Programmieren</strong><br />
1 >>> list(quads())<br />
2 ... # 1 GB, 2 GB, 3 GB, ...<br />
3 ... # ca. 3 Minuten auf 32 Bit-Rechner<br />
4 MemoryError<br />
islice(<br />
[, ], [, ])<br />
1 >>> from itertools import islice<br />
2 >>> q = quads()<br />
3 >>> i = islice(q, 0, 10)<br />
4 >>> i.next(), i.next(), i.next()<br />
5 1, 4, 9<br />
6 >>> list(i)<br />
7 [16, 25, 36, 49, 64, 81, 100]<br />
Slicen mit islice<br />
8 >>> list(islice(q, 0, 10))<br />
9 [121, 144, 169, 196, 225, 256, 289, 324,<br />
• Aufruf von islice mit start, stop, step<br />
10 >>> list(islice(q, 0, 10))<br />
• Nachbau Funktionalität<br />
[start:stop:step]<br />
11<br />
12<br />
[441, 484, 529, 576, 625, 676, 729, 784,<br />
>>> list(islice(quads(), 0, 10))<br />
13 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 242 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – itertools, Funktional Progammieren<br />
Funktional <strong>Programmieren</strong><br />
• Etwas für alle Elemente einer<br />
Liste tun<br />
• Potentiell problematisch bei<br />
unendlichen Listen<br />
Spezielle Primitive für Generatoren<br />
• Primitive mit i am Anfang*,<br />
imap, ifilter, izip<br />
• Im Modul itertools<br />
• Geben Generatoren zurück<br />
• Gleiche Funktionalität wie<br />
funktionale Primitive, nur<br />
sukkzesive<br />
1 >>> from itertools import islice, imap,<br />
2 ifilter, izip<br />
3 >>> [i for i in islice(quads(), 0, 20)<br />
4 if i%2==0]<br />
5 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />
6 >>> list(islice(ifilter(lambda x: x%2 == 0,<br />
7 quads()), 0, 10))<br />
8 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />
9 >>> gen = ifilter(lambda x: x%2 == 0, quads())<br />
10 >>> gen<br />
11 <br />
12 >>> gen.next()<br />
13 4<br />
14 >>> gen.next(),gen.next(),gen.next(),gen.next()<br />
15 (16, 36, 64, 100)<br />
16 >>> import math<br />
17 >>> list(islice(imap(math.sqrt, quads()), 9))<br />
* Keine Assoziation zu Apple-Produkten,<br />
18 [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]<br />
geht auf allen Rechnern, patent pending... :-)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 243 / 326
<strong>Programmieren</strong> in Python<br />
Generatoren<br />
Generatoren – Generator Expressions<br />
List Comprehension für<br />
Generatoren<br />
• List Comprehension direkt<br />
wieder nicht sinnvoll, da<br />
potentiell unendlich<br />
7 (1, 4, 9)<br />
• Ausdruck mit runden Klammern<br />
8 >>> list(gq)<br />
() statt eckigen Klammern []<br />
9 [16, 25, 36, 49, 64, 81]<br />
• Erzeugt dann Generator/Iterator 10 >>> gquads = (i for i in quads() if i%2 == 0)<br />
Mächtiges elegantes Konzept,<br />
nutzen!<br />
1 >>> gq = (i**2 for i in range(10))<br />
2 >>> gq<br />
3 <br />
4 >>> gq.next()<br />
5 0<br />
6 >>> gq.next(), gq.next(), gq.next()<br />
11 >>> gquads<br />
12 <br />
13 >>> gquads.next()<br />
14 4<br />
15 >>> gquads.next(),gquads.next(),gquads.next()<br />
16 (16, 36, 64)<br />
17 >>> from itertools import islice<br />
18 >>> list(islice((i for i in quads() if i%2==0)<br />
19 ,0,10))<br />
20 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 244 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen<br />
Ausnahmen – spezieller Kontrollfluss<br />
• Fokus auf Fehlerbehandlung<br />
• Erlaubt saubere Trennung von funktionalen Bestandteilen und “Rest” wie<br />
Fehlerbehandlung und Spezialfällen<br />
• Sollte nicht für allgemeinen Kontrollfluss verwendet werden<br />
Ausnahmen in Python<br />
• In Sprache integriert, einfach zu verwenden<br />
• Ähnlich zu Java<br />
Syntax<br />
• try, else, except, finally: Rahmen für Code-Strecken mit potentiellen<br />
Ausnahmen, Fangen und Verarbeiten der Ausnahmen<br />
• raise: Werfen von Ausnahmen<br />
• assert: Wie in C<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 245 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen fangen – Schema<br />
• im try-Block ausführen<br />
• Falls Ausführung Ausnahme wirft mit<br />
expect fangen<br />
• Eine oder mehrere Ausnahmen als<br />
Tupel möglich<br />
• Mehrere except möglich<br />
• Mit optionalem an Ausnahme-Instanz<br />
an binden<br />
• Falls Ausnahme gefangen<br />
entsprechenden except-Block<br />
ausführen<br />
• else-Block (optional) falls keine<br />
Ausnahme geworfen wurde<br />
• finally-Block (optional) immer, ob<br />
Ausnahme geworfen wurde (und<br />
gefangen wurde oder nicht) oder nicht<br />
try:<br />
<br />
except :<br />
<br />
except ([, ]*):<br />
<br />
except as :<br />
<br />
else:<br />
<br />
finally:<br />
<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 246 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen fangen – Beispiele, except, else<br />
1 >>> 3/0<br />
2 ZeroDivisionError: integer div.. by zero2 3/0<br />
3 >>> try:<br />
4 3/0<br />
5 except ZeroDivisionError:<br />
6 print "nicht durch Null"<br />
7 nicht durch Null<br />
8 >>> try:<br />
9 3/0<br />
0 except ZeroDivisionError as e:<br />
1 print type(e), e<br />
2 <br />
3 integer division or modulo by zero<br />
4 >>> try:<br />
5 3/0<br />
6 except IndexError:<br />
7 print "IE"<br />
8 except ZeroDivisionError:<br />
9 print "ZDE"<br />
0 ZDE<br />
1 >>> try:<br />
3 except ZeroDivisionError:<br />
4 print "ZDE"<br />
5 else:<br />
6 print "OK"<br />
7 ZDE<br />
8 >>> try:<br />
9 3/1<br />
10 except ZeroDivisionError:<br />
11 print "ZDE"<br />
12 else:<br />
13 print "OK"<br />
14 3<br />
15 OK<br />
ZeroDivisionError, builtin Ausnahmetyp<br />
Nicht gefangene Ausnahme propagiert<br />
zum TopLevel<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 247 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen fangen – Beispiele, finally<br />
1 >> try:<br />
2 ... 3/0<br />
3 ... except ZeroDivisionError:<br />
4 ... print "ZDE"<br />
5 ... finally:<br />
6 ... print "immer"<br />
7 ...<br />
8 ZDE<br />
9 immer<br />
0 >>> try:<br />
1 ... 3/1<br />
2 ... except ZeroDivisionError:<br />
3 ... print "ZDE"<br />
4 ... finally:<br />
5 ... print "immer"<br />
6 ...<br />
7 3<br />
8 immer<br />
1 >>> try:<br />
2 ... 3/0<br />
3 ... except IndexError:<br />
4 ... print "IE"<br />
5 ... finally:<br />
6 ... print "immer"<br />
7 ...<br />
8 immer<br />
9 ZeroDivisionError: integer division<br />
10 or modulo by zero<br />
finally wird immer ausgeführt<br />
Beinhaltet meist Aufräumaktionen<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 248 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen fangen – Datei-Beispiel<br />
Mit Ausnahmen arbeiten<br />
• Code unter der Annahme schreiben,<br />
dass alles funktioniert<br />
•<br />
5<br />
Ausnahme und Behandlung bei Fehler<br />
count += 1<br />
6 except IOError:<br />
Mit Dateien arbeiten<br />
7 count = 0<br />
• Zähle Zeilen in Datei<br />
8 return count<br />
• 0, wenn Datei nicht vorhanden<br />
1 def countlinesfile(filename):<br />
2 try:<br />
3 count = 0<br />
4 for _ in file(filename):<br />
1 >>> countlinesfile("/etc/passwd")<br />
2 44<br />
3 >>> countlinesfile("/GIBTESNICHT")<br />
4 0<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 249 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmeklassen – Exception, Hierarchie<br />
1 BaseException<br />
2 +-- SystemExit<br />
3 +-- KeyboardInterrupt<br />
4 +-- GeneratorExit<br />
5 +-- Exception<br />
6 +-- StopIteration<br />
7 +-- StandardError<br />
8 | +-- BufferError<br />
9 | +-- ArithmeticError<br />
0 | | +-- FloatingPointError<br />
1 | | +-- OverflowError<br />
2 | | +-- ZeroDivisionError<br />
3 | +-- AssertionError<br />
4 | +-- AttributeError<br />
5 | +-- EnvironmentError<br />
6 | | +-- IOError<br />
7 | | +-- OSError<br />
8 | | +-- WindowsError (Windows)<br />
9 | | +-- VMSError (VMS)<br />
0 | +-- EOFError<br />
1 | +-- ImportError<br />
2 | +-- LookupError<br />
3 | | +-- IndexError<br />
4 | | +-- KeyError<br />
5 | +-- MemoryError<br />
6 | +-- NameError<br />
7 | | +-- UnboundLocalError<br />
1 | +-- ReferenceError<br />
2 | +-- RuntimeError<br />
3 | | +-- NotImplementedError<br />
4 | +-- SyntaxError<br />
5 | | +-- IndentationError<br />
6 | | +-- TabError<br />
7 | +-- SystemError<br />
8 | +-- TypeError<br />
9 | +-- ValueError<br />
10 | +-- UnicodeError<br />
11 | +-- UnicodeDecodeError<br />
12 | +-- UnicodeEncodeError<br />
13 | +-- UnicodeTranslateError<br />
14 +-- Warning<br />
15 +-- DeprecationWarning<br />
16 +-- PendingDeprecationWarning<br />
17 +-- RuntimeWarning<br />
18 +-- SyntaxWarning<br />
19 +-- UserWarning<br />
20 +-- FutureWarning<br />
21 +-- ImportWarning<br />
22 +-- UnicodeWarning<br />
23 +-- BytesWarning<br />
Eigene Ausnahmeklassen passend<br />
ableiten<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 250 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen werfen<br />
Ausnahmen werfen mit raise<br />
• raise : Wirft Ausnahme der<br />
Klasse , muss von<br />
BaseException erben<br />
• raise : Wirft Ausnahme der<br />
Instanz , muss Instanz von<br />
BaseException ein<br />
Instanzen oder Klassen werfen<br />
• Instanz um Daten mitzugeben<br />
• Häufig sind Daten ein String<br />
Vordefinierte Ausnahmen verwendbar<br />
1 >>> raise Exception("nix geht")<br />
2 Exception: nix geht<br />
1 >>> class MeineAusnahme(object):<br />
2 pass<br />
3 >>> raise MeineAusnahme<br />
4 TypeError: exceptions must be old-style<br />
5 classes or derived from<br />
6 BaseException, not type<br />
7<br />
8 >>> class MeineAusnahme(Exception):<br />
9 pass<br />
10 >>> raise MeineAusnahme<br />
11 __main__.MeineAusnahme<br />
12<br />
13 >>> try:<br />
14 msg="Weil es nicht geht"<br />
15 raise MeineAusnahme(msg)<br />
16 except MeineAusnahme as inst:<br />
17 print "Warum?", inst<br />
18 Warum? Weil es nicht geht<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 251 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen mit assert<br />
Zusicherungen mit assert<br />
• : ein Test<br />
• Sobald Test äquivalent zu False<br />
evaluiert, AssertionError<br />
Optimierung<br />
• Gesteuert durch globale Variable<br />
__debug__<br />
assert , <br />
if __debug__:<br />
if not :<br />
raise AssertionError()<br />
• Beim Übersetzen mit -O wird<br />
__debug__ = False gesetzt bzw. der<br />
Bytecode komplett entfernt<br />
Benutzung<br />
• Schleifeninvarianten, Vor- und<br />
Nachbedingungen<br />
• Frühzeitige Fehlererkennung<br />
• Lauffähige Dokumentation<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 252 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen mit assert – Beispiel<br />
Zerlegen von einem String<br />
• Wir gehen davon aus, dass der String<br />
immer genau einen Doppelpunkt<br />
enthält<br />
• Was passiert im Fehlerfall?<br />
Defensiv programmieren<br />
• Früh fehlschlagen, statt erst mal weiter<br />
machen; assert<br />
• Fehlermeldungen werden besser<br />
1 def zerlege_nonsafe(s):<br />
2 l = s.split(":")<br />
3 return (l[0], l[1])<br />
4 def zerlege_safe(s):<br />
5 l = s.split(":")<br />
6 assert len(l) == 2, l<br />
7 return (l[0], l[1])<br />
1 >>> zerlege_nonsafe("a:b:c")<br />
2 (’a’, ’b’)<br />
3 >>> zerlege_safe("a:b:c")<br />
4 assert len(l) == 2, l<br />
5 AssertionError: [’a’, ’b’, ’c’]<br />
6 >>> zerlege_nonsafe("a")<br />
7 return (l[0], l[1])<br />
8 IndexError: list index out of range<br />
9 >>> zerlege_safe("a")<br />
10 assert len(l) == 2, l<br />
11 AssertionError: [’a’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 253 / 326
<strong>Programmieren</strong> in Python<br />
Ausnahmen<br />
Ausnahmen statt “Check then Act”-Fehler<br />
Aufgabe<br />
• Überprüfe die Existenz einer Datei<br />
• Falls vorhanden, erste Zeile zurück<br />
• Falls nicht vorhanden, hart beenden<br />
• Es darf kein IOError geworfen werden<br />
Ansätze<br />
• “Check then act”, fehlerhaft<br />
• Es kann passieren, dass jemand<br />
zwischen Check Zeile 4 und<br />
verwenden, die Datei entfernt<br />
• Es wird dann doch IOError geworfen<br />
• Mach es; melde, wenn es nicht geht<br />
• Kein Problem, sobald die Datei<br />
geöffnet werden konnte, ist sie da<br />
Ein IOError wäre natürlich doch die<br />
bessere Variante, statt hart zu beenden<br />
1 def get_status(fname):<br />
2 if not os.path.exists(fname):<br />
3 print "file not found"<br />
4 sys.exit(-1)<br />
5 return file(fname).readline()<br />
1 def get_status(fname):<br />
2 try:<br />
3 return file(fname).readline()<br />
4 except (IOError, OSError) as e:<br />
5 print "problem; exiting: "+str(e)<br />
6 sys.exit(-1)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 254 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Bibliotheken – Module in der Standardbibliothek<br />
Python-Bibliotheken – viel im Standard<br />
• Als Module/Pakete verfügbar<br />
• Breites Angebot, “Batteries included”,<br />
ausführlich dokumentiert<br />
Beispiele:<br />
• os: Systemnah, Verzeichnisse/Dateien<br />
sys: Python-Umgebung<br />
• unittest: Unit Testing<br />
pickle: Objektpersistenz<br />
urllib, cgi, imap, ftp, http: Web,<br />
Internet Protokolle<br />
PIL: Bildbearbeitung (nicht standard)<br />
turtle: Einfachstgraphik, Tkinter<br />
Tkinter, wx, qt: GUI, alle OS<br />
pygame: Spielend Spiele spielen<br />
re: Reguläre Ausdrücke<br />
1 >>> import os<br />
2 >>> os.getcwd()<br />
3 ’/home/mi/ssinn001’<br />
4 >>> os.chdir("/usr/share/games/fortunes")<br />
5 >>> os.getcwd()<br />
6 ’/usr/share/games/fortunes’<br />
7 >>> [x for x in os.listdir(os.getcwd())<br />
8 if x.endswith(".dat")]<br />
9 [’fortunes.dat’, ’riddles.dat’,<br />
10 ’literature.dat’]<br />
11 >>> import sys<br />
12 >>> sys.argv<br />
13 [’’]<br />
14 >>> import re<br />
15 >>> re.findall(r’ab+c’, "abbcdsabcab")<br />
16 [’abbc’, ’abc’]<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 255 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Unit Testing<br />
Ziel<br />
• Funktionalitäten feingranular testen<br />
• Automatisierung, einfache Verwaltung<br />
von Testfällen<br />
Umsetzung – unittest, Verwendung<br />
• Anlehnung an JUnit<br />
• Von Klasse TestCase erben<br />
• Testfunktionen mit test_ am Anfang<br />
des Namens<br />
• Zusicherung, self.: Erwartet<br />
• assert_: True, wie assert<br />
• assertEqual: Zwei gleich Parameter<br />
• assertRaises: Passende Ausnahme<br />
• setUp, tearDown: Vor/nach jedem Test,<br />
Test Fixture<br />
• Aufrufen mit unittest.main()<br />
import unittest<br />
class (unittest.TestCase):<br />
[def setUp(self):<br />
]<br />
...<br />
[def tearDown(self):<br />
]<br />
...<br />
[def test(self):<br />
...<br />
[self.assert_() |<br />
[self.assertEqual(, ) |<br />
[self.assertRaises()]*<br />
...<br />
]*<br />
if __name__ == ’__main__’:<br />
unittest.main()<br />
Anpassbar, flexibel, weitere Optionen<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 256 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Unit Testing – Beispiel<br />
Beispieltest “Ist Primzahl?”<br />
• Importieren Modul<br />
• Zu testende Funktion is_prim,<br />
meist in anderem Modul<br />
• Testfunktionen<br />
• Start der Tests<br />
Ausgabe<br />
..<br />
• Zwei Tests ok durchgelaufen<br />
-------------------------------<br />
Ran 2 tests in 0.000s<br />
OK<br />
1 import unittest<br />
2<br />
3 def is_prim(x):<br />
4 if x < 2: return False<br />
5 ts = [t for t in range(2, x) if x%t==0]<br />
6 return not ts<br />
7<br />
8 class PrimTest(unittest.TestCase):<br />
9 def setUp(self):<br />
10 self.r = range(1, 101) # 1..100<br />
11 self.ps = 25 # 25 Primzahlen<br />
12 def testPrim1(self):<br />
13 self.assert_(is_prim(2))<br />
14 self.assert_(not is_prim(4))<br />
15 self.assertEqual(is_prim(7), True)<br />
16 def testPrim2(self):<br />
17 prims = filter(is_prim, self.r)<br />
18 self.assertEqual(len(prims), self.ps)<br />
19 if __name__ == ’__main__’:<br />
20 unittest.main()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 257 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Pickle – Einfache Objektpersistenz<br />
Ziel<br />
• Serialisierung von Objektinstanzen<br />
• Plattform- und versionsunabhängig<br />
• Kein Persistenzframework<br />
Umsetzung – pickle<br />
• Für eingebaute Standardtypen<br />
• Hierarchien und Referenzen<br />
• Klassen, aber nur Instanzen<br />
Beispiel<br />
• Schreiben mit dump<br />
• Lesen mit load<br />
Aclass.py<br />
1 class A(object):<br />
2 def __init__(self, end=3):<br />
3 self.lis = range(1, end)<br />
4 def __str__(self):<br />
5 return "A["+str(self.lis)+"]"<br />
6 __repr__ = __str__<br />
1 import pickle<br />
2 import Aclass<br />
3<br />
4 tup=(1, 1.0, 1+1j, (1,), "1", {1:2})<br />
5 lis=[1,2,3]<br />
6 lis.append(lis)<br />
7 alis=[Aclass.A(i) for i in range(1, 6)]<br />
8 pickle.dump((tup, lis),<br />
9 file("tuplis.pickle", "wb"))<br />
10 pickle.dump(alis,<br />
11 file("alis.pickle", "wb"))<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 258 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Pickle – Einlesen<br />
Beispiel<br />
• Referenzen, auch zirkuläre,<br />
werden richtig wiederhergestellt<br />
• Instanzen von Objekten werden<br />
richtig wieder instanziiert<br />
• Klasse/Modul muss verfügbar<br />
sein, wird nicht gepickelt<br />
• Einladen über import muss<br />
klappen<br />
Erweiterungen<br />
• Pickeln von Instanzen über<br />
Methoden beeinflussbar<br />
• Pickeln von Klassen oder<br />
Funktionen nicht möglich<br />
• cPickle, schneller<br />
• Unterschiedliche<br />
Protokollversionen<br />
1 >>> import pickle<br />
2 >>> f = file("tuplis.pickle", "rb")<br />
3 >>> t, l = pickle.load(f)<br />
4 >>> t<br />
5 (1, 1.0, (1+1j), (1,), ’1’, {’1’: ’eins’})<br />
6 >>> l<br />
7 [1, 2, 3, [...]]<br />
8 >>> al = pickle.load(file("alis.pickle","rb"))<br />
9 >>> al<br />
10 [A[[]], A[[1]], A[[1, 2]], A[[1, 2, 3]],<br />
11 A[[1, 2, 3, 4]]]<br />
12 >>> al[0].__class__<br />
13 <br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 259 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Internetdaten verarbeiten<br />
• rfc822, mimetools, mimetypes, mailcap, imaplib, mailbox, smtplib, nntplib:<br />
Email- und News-spezifische Bibliotheken<br />
• uu, binascii: Konvertierungen<br />
• SocketServer, SimpleHTTPServer, ftplib: Protokollimplementierungen<br />
• urllib, urllib2, urlparse: URL-Manipulation, Anfragen<br />
1 >>> import urllib2, re<br />
2 >>> s = urllib2.urlopen("http://www.heise.de/newsticker/").read()<br />
3 >>> s[:100]<br />
4 ’\n\n\n\n \n<br />
5 \n\n 7-Tage-News | heise online\n\n ’<br />
6 >>> hl = re.findall(r’(.*?)’, s)<br />
7 >>> for t in [t for t in hl if "Android" in t]: print t<br />
8 Unzuverlaessige Trojaner-Warnungen durch Android 4.2<br />
9 LTE-Smartphone mit Android 4.0 von HTC<br />
0 Java-IDE IDEA 12: neue Oberflaeche, neuer Compiler-Modus, neuer Android-Designer<br />
1 Gingerbread bleibt die am meisten benutzte Android-Version<br />
2 Aktualisierte Maps-API fuer Android-Entwickler<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 260 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Turtle Graphics<br />
Turtle Graphics<br />
• Einfache Graphiken wie mit einem Stift<br />
erstellen, “Logo, Programming for<br />
Kids”<br />
• Zeichenfläche mit Mitte 0,0<br />
• Kommandos up (Stift hoch), down (Stift<br />
auf Papier), goto (Bewege Stift), . . .<br />
1 from turtle import *<br />
2 down()<br />
3 goto(100, 0)<br />
4 goto(0, -100)<br />
5 goto(100, -100)<br />
6 up()<br />
7 goto(0, 0)<br />
8 down()<br />
9 for i in range(100):<br />
0 goto(i, i**2/100.)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 261 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Bildbearbeitung mit PIL<br />
Python Imaging Library (PIL)<br />
• C-Erweiterung<br />
• Nicht im Standard<br />
• Einfach, mächtig<br />
• ([noch] nur Python 2.x)<br />
1 >>> import Image<br />
2 >>> im=Image.open("lena.png")<br />
3 >>> im.show()<br />
4 >>> im2=im.resize(map(lambda x: x*2,<br />
5 im.size))<br />
6 >>> im2.show()<br />
7 >>> im3=im.rotate(45)<br />
8 >>> im3.show()<br />
9 >>> import ImageFilter<br />
0 >>> im4=im.filter(ImageFilter.FIND_EDGES)<br />
1 >>> im4.show()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 262 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
Spiele mit pygame<br />
Spiele <strong>Programmieren</strong> mit pygame<br />
• Kombination von Bibliotheken<br />
• 2D/3D-Grafik, Sound, . . .<br />
• Abstraktionen (Sprites, Kollision)<br />
Beispiel<br />
• Viele, viele Logos<br />
1 import sys, pygame<br />
2<br />
3 pygame.init()<br />
4 bild = pygame.image.load("hsrm.png")<br />
5 groesse = breite, hoehe = 800, 600<br />
1 if __name__ == ’__main__’:<br />
2 main()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 263 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
pygame – Ein Bild bewegt sich<br />
Bewegung: bewege<br />
• Innerhalb eines Rechtecks<br />
• Bei Wand (Ende Rechteck),<br />
ändere Bewegungsrichtung<br />
(wieder zurück)<br />
• Bewege!<br />
Anzeige, Animation: main<br />
• Initialisierung Bildschirm,<br />
Bewegungsrichtung<br />
• GameLoop<br />
• Bearbeite (ignoriere) Events<br />
• Hintergrund<br />
• Bewege Bild<br />
• Bild auf (virtuellen) Bildschirm<br />
• Bringe vorbereiteten<br />
(flackerfreien) Bildschirm zur<br />
Ansicht<br />
1 def bewege(rect, direction):<br />
2 if rect.left < 0 or rect.right > breite:<br />
3 direction[0] = -direction[0]<br />
4 if rect.top < 0 or rect.bottom > hoehe:<br />
5 direction[1] = -direction[1]<br />
6 return rect.move(direction)<br />
7<br />
8 def main():<br />
9 screen = pygame.display.set_mode(groesse)<br />
10 bild_rect = bild.get_rect()<br />
11 direction = [1,1] # bewegungsrichtung<br />
12 while True:<br />
13 for event in pygame.event.get():<br />
14 if event.type == pygame.QUIT:<br />
15 sys.exit()<br />
16 screen.fill((50, 130, 40)) # gruen<br />
17 bild_rect = bewege(bild_rect, direction)<br />
18 screen.blit(bild, bild_rect)<br />
19 pygame.display.flip()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 264 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
pygame – Besser, Klasse für Spielobjekte<br />
Logo-Klasse<br />
• Spielobjekt, Bild parametrisiert<br />
• Taucht zufällig intial irgendwo<br />
auf<br />
• Bewegt sich bei<br />
Richtungsänderung an einer<br />
Wand zufällig (1–3) anders<br />
schnell weiter<br />
• Kann sich selbst zeichnen<br />
Logos, die verwendet werden<br />
• hsrm.png<br />
• hsrml.png<br />
• pygame.png<br />
1 class Logo(object):<br />
2 def __init__(self,screen,fname="hsrm.png"):<br />
3 self.screen = screen<br />
4 self.bild = pygame.image.load(fname)<br />
5 r = self.rect = self.bild.get_rect()<br />
6 r.left=random.randint(0,breite-r.width)<br />
7 r.top=random.randint(0,hoehe-r.height)<br />
8 self.dir = [random.randint(1,3),<br />
9 random.randint(1,3)]<br />
10 def bewege(self):<br />
11 if self.rect.left < 0:<br />
12 self.dir[0] = random.randint(1, 3)<br />
13 elif self.rect.right > breite:<br />
14 self.dir[0] = -random.randint(1, 3)<br />
15 if self.rect.top < 0:<br />
16 self.dir[1] = random.randint(1, 3)<br />
17 elif self.rect.bottom > hoehe:<br />
18 self.dir[1] = -random.randint(1, 3)<br />
19 self.rect = self.rect.move(self.dir)<br />
20 self.screen.blit(self.bild, self.rect)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 265 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
pygame – Besser, Loop<br />
Game Loop, feste Framerate<br />
• Frames per Second (FPS)<br />
• Setzen mit clock.tick(FPS),<br />
• wartet/schläft gegebenenfalls<br />
Neues Feature<br />
• Neues Objekt bei jedem Klick<br />
(Maus loslassen)<br />
• Grosses Logo<br />
Position setzen<br />
class Logo(object): ...<br />
1 def setpos(self, pos):<br />
2 self.rect.left = pos[0]<br />
3 self.rect.top = pos[1]<br />
1 def main():<br />
2 screen=pygame.display.set_mode(groesse)<br />
3 clock=pygame.time.Clock()<br />
4 logos=[Logo(screen) for i in range(17)]<br />
5 while True:<br />
6 clock.tick(60)<br />
7 for event in pygame.event.get():<br />
8 if event.type == pygame.QUIT:<br />
9 sys.exit()<br />
10 if event.type == pygame.MOUSEBUTTONUP:<br />
11 if event.button == 1:<br />
12 logo=Logo(screen,"hsrml.png")<br />
13 logo.setpos(event.pos)<br />
14 logos.append(logo)<br />
15 screen.fill((50,130,40))<br />
16 for logo in logos:<br />
17 logo.bewege()<br />
18 pygame.display.flip()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 266 / 326
<strong>Programmieren</strong> in Python<br />
Bibliotheken<br />
pygame – Mehr, Kollisionserkennung<br />
Kollisionserkennung<br />
• Wann berühren sich zwei<br />
Objekte<br />
• In pygame geschenkt<br />
Code-Änderung<br />
• Global merken, welche Objekte<br />
es gibt<br />
• Prüfen ob Kollision, wenn ja,<br />
dann alternatives Bild<br />
• Kollisionserkennung vieler<br />
Objekte hier naiv (quadratisch)<br />
• Bewegen über alle Objekte<br />
1 class Logo(object):<br />
2 logos = []<br />
3 def __init__(self, ...):<br />
4 ...<br />
5 self.alt_bild=pygame.image.load("pygame.p<br />
6 Logo.logos.append(self)<br />
7 def bewege(self):<br />
8 ...<br />
9 bild = self.alt_bild<br />
10 if self._collides_with()<br />
11 else self.bild<br />
12 self.screen.blit(bild, self.rect)<br />
13 def _collides_with(self):<br />
14 return [logo for logo in Logo.logos<br />
15 if logo != self<br />
16 if self.rect.colliderect(logo.rect)]<br />
17 def main():<br />
18 ...<br />
19 for logo in Logo.logos:<br />
20 ...<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 267 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Reguläre Ausdrücke<br />
Reguläre Ausdrücke<br />
• “Matchen”, finde passenden String<br />
• Flexibles Matchen auf “Pattern” mit Sonderzeichen<br />
• Erweiterte reguläre Ausdrücke, nicht Wildcards<br />
• In Java, Python, . . . verfügbar, Kommandozeile mit egrep<br />
Reguläre Ausdrücke in <strong>Skript</strong>sprachen<br />
• Spezielle Bibliotheken (Python, PHP, Java) oder Teil der Sprache (Perl, awk)<br />
• Kompilation des Patterns, Ausführen auf C-basierter Engine<br />
Einsatz<br />
• Stringverarbeitung, Extraktion, Suchen/Ersetzen<br />
• Test auf syntaktische Korrektheit (Email-Adresse, Telefonnummer)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 268 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Matchen mit einfachen Patterns<br />
Teil des Strings<br />
• Ein Pattern beschreibt einen Teil des<br />
zu durchsuchenden Strings<br />
Pattern – Zeichen matchen sich selbst<br />
• Zum Beispiel matcht das Pattern fahr<br />
den String erfahren<br />
Groß- und Kleinschreibung wird<br />
unterschieden<br />
• Das Pattern Fahr macht nicht den<br />
String erfahren<br />
Sonderzeichen haben spezielle<br />
Bedeutung<br />
• . ˆ$ * + ? { } [ ] \ | ( )<br />
<br />
<br />
fahr<br />
erfahren<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 269 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Auswahlbereiche für ein Zeichen<br />
Auswahl mit []<br />
[abcde]<br />
[a-z]<br />
[a-zA-Z]<br />
[abc$ˆ]<br />
[ˆa-z]<br />
[ab\cd]<br />
Einzelnes Zeichen: Matcht entweder a, b, c, d oder e<br />
Bereich: Matcht jeden (einen) Kleinbuchstaben (ASCII)<br />
Bereich: Matcht Groß- und Kleinbuchstaben<br />
Sonderzeichen nicht aktiv in Bereichen. Matcht a, b, c, $ oder ˆ<br />
ˆam Anfang negiert den Bereich. Matcht alles außer Kleinbuchstaben<br />
\ hebt die besondere Bedeutung auf. Matcht a, b, \, c oder d<br />
Vordefinierte Auswahlbereiche<br />
\d Alle Ziffern, [0-9]<br />
\D Alles außer Ziffern, [ˆ0-9]<br />
\s Whitespace, [ \t\n\r\f\v]<br />
\S Alles außer Whitespace,<br />
[ˆ \t\n\r\f\v]<br />
\w Alphanumerische Zeichen,<br />
[a-zA-Z0-9]<br />
\W Alles außer alphanumerischen Zeichen,<br />
[ˆa-zA-Z0-9]<br />
Auch für Nicht-ASCII Zeichensätze<br />
• Beispiel Deutsch: Umlaute<br />
äöüÄÖÜß werden von \w erkannt<br />
• Achtung: locale-Einstellungen<br />
werden berücksichtigt<br />
• Unicode? wieder alles anders...<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 270 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Wiederholungen und Gruppierungen<br />
matcht , , ...<br />
Pa*gei Pgei, Pagei, Paagei, ...<br />
Pa+gei Pagei, Paagei, ...<br />
Pa?gei<br />
Pgei, Pagei und sonst nichts<br />
P[ae]*gei,<br />
Pgei, Pagei, Pegei, Paagei, Paegei, Peagei<br />
wie P(a|e)*gei Peegei, Paaagei, ...<br />
(Pap|Mam)agei<br />
Papagei, Mamagei und sonst nichts<br />
(Pa)+gei Pagei, PaPagei, PaPaPagei, . . .<br />
Pa(pa)+gei Papagei, Papapagei, . . .<br />
Pa(pa){1,3}gei<br />
Papagei, Papapagei, Papapapagei und sonst nichts<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 271 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Besondere Zeichen und Bedeutung<br />
. beliebiges Zeichen {m,n} Wiederholung, mindestens<br />
m mal und maximal n mal<br />
* Wiederholung 0, 1 oder<br />
{n} Exakt n mal<br />
mehrfach<br />
? Wiederholung 0 oder 1 mal [ Beginn Auswahl aus Zeichen<br />
+ Wiederholung 1 oder mehrfach ] Ende Auswahl aus Zeichen<br />
( Beginn einer Gruppierung ˆ Anfang String/Zeile<br />
) Ende einer Gruppierung [ˆ Negation/Auswahl<br />
{ Beginn explizit gezählte<br />
$ Ende String/Zeile<br />
Wiederholung<br />
} Ende explizit gezählte<br />
Wiederholung<br />
| Oder-Auswahl von<br />
Gruppierungen<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 272 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Gierige Ausführung<br />
Von links nach rechts<br />
• Der erste passende Teilausdruck wird<br />
gematcht<br />
• Später passende Teilausdrücke<br />
werden ignoriert<br />
a[bc]+<br />
xabdyaabc<br />
matcht ab,<br />
nicht abc<br />
So viel wie möglich<br />
• Bei dem ersten passenden<br />
Teilausdruck<br />
• So viel wie möglich Zeichen in den<br />
Match bringen<br />
a[bc]+<br />
xadyaabbbcccd<br />
matcht abbbccc,<br />
nicht Teil davon<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 273 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Beispiele<br />
Binärzahlen (0|1[01]*) ohne führende Nullen<br />
Ganze Zahlen 0|([1-9][0-9]*) ohne führende Nullen<br />
Pi 3\.14<br />
Emailadresse \w+([.-]\w+)*@[a-z]\w+(\.[a-z]\w+)+<br />
Einfaches Ausprobieren in der Shell (bash)<br />
• echo | egrep "" # matcht Teilstring<br />
• echo | egrep "ˆ()$" # exakter Match<br />
Beispiel<br />
• $ echo "11110" | egrep "ˆ(0|(1[01]*))$"<br />
11110<br />
$<br />
• $ echo "011110" | egrep "ˆ(0|(1[01]*))$"<br />
$<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 274 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Reguläre Ausdrücke und Wildcards<br />
Reguläre Ausdrücke<br />
Wildcards<br />
Matchen von Strings<br />
In Perl, Python, egrep, . . .<br />
(Meist) erweiterte reguläre Ausdrücke<br />
Beispiel Unterschiede<br />
a* passt auf beliebig viele a’s; * steht<br />
für die Wiederholung des vorherigen<br />
Zeichens<br />
Matchen von Strings<br />
In Shell, DOS, grep<br />
Standard Wildcards<br />
Beispiel Unterschiede<br />
a* passt auf jeden String der mit a<br />
beginnt; * steht für beliebige<br />
Zeichenfolge<br />
a? passt auf leeres Wort oder a a? passt auf jeden zwei Zeichen<br />
langen String, der mit a beginnt<br />
. . .<br />
Weitere Probleme<br />
• Groß-/Kleinschreibung unterschieden?<br />
• Das $-Zeichen als Beginn einer Variable<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 275 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Literatur und Online-Quellen für Reguläre Ausdrücke<br />
Reguläre Ausdrücke allgemein<br />
• http://<br />
regexp-evaluator.de<br />
/tutorial/<br />
• Die Referenz:<br />
Jeffrey E.F. Friedel<br />
Reguläre Ausdrücke<br />
O’Reilly<br />
Reguläre Ausdrücke in Python<br />
• http://docs.python.org/2.7/library/re.html<br />
• http://docs.python.org/dev/howto/regex.html<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 276 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
re-Modul – Reguläre Ausdrücke in Python<br />
Reguläre Ausdrücke in Python<br />
• re-Modul<br />
• Matche, modifiziere, zerteile, ersetze,<br />
. . .<br />
• Kompilation des “Patterns”<br />
• Ausführen auf C-Engine<br />
Ausführlich dokumentiert – Lesen!<br />
Einfaches Beispiel<br />
• Pattern kompilieren<br />
• Matchen<br />
• Ergebnis ausgeben<br />
• oder alles auf einmal<br />
1 >>> import re<br />
2 >>> pattern = re.compile("[a-z]+")<br />
3 >>> match = pattern.match("abc")<br />
4 >>> match.group()<br />
5 ’abc’<br />
6<br />
7 >>> re.match(r’[a-z]+’, "abc").group()<br />
8 ’abc’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 277 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Beispiel – Kompilieren und Matchen<br />
Kompilieren<br />
• Modul-Funktion compile<br />
• Kompilieren eines regulären<br />
Ausdrucks erzeugt Patternobjekt<br />
Matchen<br />
• Methoden des Patternobjekts<br />
• Mit match Suche in einem String ab<br />
Anfang<br />
• Mit search Suche in einem String<br />
irgendwo<br />
• Ergebnis ist Matchobjekt wenn<br />
erfolgreich, sonst None<br />
• Aus Match-Objekt mit group den<br />
Match (String) extrahieren<br />
1 >>> import re<br />
2 >>> pattern = re.compile(r’[a-z]+’)<br />
1 >>> match = pattern.match(’abcABC’)<br />
2 >>> match.group()<br />
3 ’abc’<br />
4 >>> match = pattern.match(’ABCabcABC’)<br />
5 >>> match<br />
6 >>> print match<br />
7 None<br />
8 >>> match.group()<br />
9 AttributeError: ’NoneType’ object has no<br />
10 >>> match = pattern.search(’ABCabcABC’)<br />
11 >>> match.group()<br />
12 ’abc’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 278 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Beispiel – Optionen und Kompakt<br />
Optionen<br />
• re.IGNORECASE ignorieren von<br />
Groß-/Kleinschreibung<br />
• Weitere Optionen: re.LOCALE,<br />
re.MULTILINE, re.DOTALL,<br />
re.UNICODE, . . .<br />
• Optionen mit Oder | verknüpft<br />
Kompakter Code<br />
• re-Modul stellt Funktionen zur<br />
Verfügung<br />
1 >>> pattern = re.compile(r’[a-z]+’,<br />
2 re.IGNORECASE)<br />
3 >>> match = pattern.search(’ABCabcABC’)<br />
4 >>> match.group()<br />
5 ’ABCabcABC’<br />
1 >>> re.search(’[a-z]+’,<br />
2 "ABCabcABC")<br />
3 <br />
4 >>> re.search(’[a-z]+’,<br />
5 "ABCabcABC").group()<br />
6 ’abc’<br />
7<br />
• Alles in einem Ausdruck möglich >>> re.search(’[a-z]+’,<br />
8 "ABCabcABC",<br />
9 re.IGNORECASE).group()<br />
10 ’ABCabcABC’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 279 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Backslash-Zirkus<br />
Problem<br />
• Mit \ (Backslash) werden Sonderzeichen Ihres besonderen Status beraubt<br />
• Viele Backslashes in Python sind ein Problem<br />
Lösung<br />
• Text \section matchen benötigt \\\\section als Pattern<br />
• Ein \ um das Backslash im Python String zu haben<br />
• Die beiden anderen um das zweite Backslash für den regulären Ausdruck zu haben<br />
• Benutze “raw” Strings in dem alle Zeichen ohne Sonderstatus vorkommen<br />
• r"\\section" entspricht "\\\\section"<br />
1 >>> re.search(’\\\\section’, "dies ist \\section wichtig").group()<br />
2 ’\\section’<br />
3 >>> print re.search(’\\\\section’, "dies ist \\section wichtig").group()<br />
4 \section<br />
5 >>> re.search(r’\\section’, "dies ist \\section wichtig").group()<br />
6 ’\\section’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 280 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Gruppierungen<br />
Gruppierungen<br />
• Teilbereich im Pattern, die<br />
referenziert werden können<br />
• Klammern im Pattern<br />
Zugriff auf Gruppierungen<br />
• groups(): Alle Gruppierungen<br />
• groups(i): Die i.-te Gruppe,<br />
definiert durch i öffnende<br />
Klammern im Pattern<br />
• group(0), group(): Der gesamte<br />
Match<br />
Zurückreferenzieren durch \i im Pattern<br />
• Beispiel: Suche doppeltes<br />
Vorkommen<br />
1 >>> pat = r’(a(b)c)d’<br />
2 >>> s = "abcd"<br />
3 >>> re.search(pat, s).groups()<br />
4 (’abc’, ’b’)<br />
5 >>> re.search(pat, s).group()<br />
6 ’abcd’<br />
7 >>> re.search(pat, s).group(0)<br />
8 ’abcd’<br />
9 >>> re.search(pat, s).group(1)<br />
10 ’abc’<br />
11 >>> re.search(pat, s).group(2)<br />
12 ’b’<br />
13 >>> re.search(pat, s).group(3)<br />
14 IndexError: no such group<br />
15 >>> re.search(pat, s).group(0, 1, 2)<br />
16 (’abcd’, ’abc’, ’b’)<br />
17 >>> s = "Ist doppelt doppelt drin"<br />
18 >>> pat = r’([a-z]+ )\1’<br />
19 >>> print re.search(pat, s).group()<br />
20 doppelt doppelt<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 281 / 326
<strong>Programmieren</strong> in Python<br />
Reguläre Ausdrücke<br />
Modifizieren von Strings<br />
Zerteilen von Strings<br />
• re.split(, )<br />
• Gibt Liste von Strings zurück<br />
• Zerteilt bei jedem<br />
Match von <br />
Suchen und Ersetzen<br />
• re.sub(,,)<br />
• Gibt neuen String zurück<br />
• Bei jedem Match von <br />
in wird <br />
stattdessen eingesetzt<br />
1 >>> pat = r’\W+’<br />
2 >>> s = "Das ist ein netter kleiner Test"<br />
3 >>> re.split(pat, s)<br />
4 [’Das’,’ist’,’ein’,’netter’,’kleiner’,’Test’]<br />
1 >>> pat = ’(blaue|weisse|rote)’<br />
2 >>> neu = "bunte"<br />
3 >>> s = "Die blaue Socke und der rote Ball"<br />
4 >>> re.sub(pat, neu, s)<br />
5 ’Die bunte Socke und der bunte Ball’<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 282 / 326
Thread-Programmierung<br />
Einführung<br />
Multitasking<br />
Multitasking<br />
• Mehrere Dinge “gleichzeitig” tun<br />
• Erwartetes Verhalten auf Rechnern<br />
• Musik, Web (+ Animation), Download<br />
• Ein “Ding” ist meist ein Prozess<br />
• Eigener Speicher<br />
• Eigener Ausführungsstrang/-faden<br />
• Beispiel: P1, P2 und P3/4 parallel; P4 nach nach P3<br />
Prozessoren/Kerne und Prozesse<br />
• Ausführung der Prozesse auf Prozessoren/Kernen<br />
• Multitasking auch bei einem Kern<br />
• Zeitscheiben unterteilen Prozessorzeit<br />
• Jeder Prozess erhält abwechselnd eine (sehr sehr<br />
kleine) Zeitscheibe<br />
• Bei vielen Kernen mehr (parallele Zeitscheiben)<br />
• Aus Benutzersicht alles quasi gleichzeitig<br />
Zeit<br />
Zeit<br />
P3<br />
P1 P2<br />
P4<br />
P3<br />
P1 P2<br />
P4<br />
Zeitscheibe<br />
Prozessor<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 283 / 326
Thread-Programmierung<br />
Einführung<br />
Threads<br />
Prozesse<br />
• Eigener Speicher, eigener Ausführungsfaden<br />
P1<br />
P2<br />
• Fehler in einem Prozess betrifft nur diesen Prozess<br />
• Bei C mit Speicherfehler (Segmentation fault) lief alles<br />
außer Ihrem Prozess weiter<br />
• Schwergewichtige Umschaltung der Zeitscheiben,<br />
viel Aufwand je Kontextwechsel<br />
Zeit<br />
Threads<br />
• Teilen sich Speicher, eigener Ausführungsfaden<br />
P1<br />
P2<br />
• Threads innerhalb eines Prozesses<br />
• Leichtgewichtiges Umschalten der Zeitscheiben,<br />
weniger Aufwand je Kontextwechsel<br />
T1 T2 T3<br />
T4<br />
T5<br />
T6<br />
T7<br />
• Verteilung Zeitscheiben auf alle Threads aller<br />
Prozesse (bei Betriebssystemunterstützung)<br />
Zeit<br />
• Nebenläufigkeit als Programmiermodell<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 284 / 326
Thread-Programmierung<br />
Einführung<br />
Thread-Programmierung<br />
<strong>Programmieren</strong> mit Nebenläufigkeit<br />
• Mehrere Ausführungsstränge/-fäden quasi gleichzeitig bei<br />
gemeinsamen Daten/Ressourcen<br />
• Tausende von Threads möglich, leichtgewichtiger<br />
• Komplex und mächtig bei Verwendung<br />
Weit verbreitet in Programmierumgebungen<br />
• In C/C++ mit Bibliotheken, nutzen Betriebssystemunterstützung<br />
• In Java Teil der Sprache/JVM mit Bibliotheken<br />
• In Python ähnliche API wie in Java<br />
Einsatzgebiete<br />
• Kein Warten bei I/O-Operationen, Überbrücken Latenzen bei<br />
Netzwerkkommunikation; zum Beispiel bei UI kein “Einfrieren der UI” mehr<br />
• Nutzung von Mehrkernarchitekturen, parallele Algorithmen, Verteilen der<br />
Arbeitslast auf mehrere Kerne<br />
• Leider nicht mit CPython (oder PyPy) aber mit Jython<br />
• In CPython ist Alternative multiprocessing-Modul<br />
Globale Daten<br />
T1 T2 T3<br />
T4<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 285 / 326
Thread-Programmierung<br />
Thread-Programmierung in Python<br />
Thread-Programmierung in Python<br />
Java-Style<br />
• Thread-API modelliert nach Java<br />
• threading-Modul, Thread-Klasse<br />
• Methode run überschreiben<br />
Beispiel – die i.-te Primzahl<br />
• Primzahlgenerator prim gegeben<br />
• Klasse erbt von threading.Thread<br />
• Bei Initialisierung i merken<br />
• Methode run, solange Primzahlen bis<br />
i.-te erreicht, Ausgabe<br />
• Instanzvariablen und lokale Variablen<br />
für den Thread<br />
• p und e sind thread-lokale Variablen<br />
(auf dem Stack)<br />
1 import threading, sys<br />
2 from primegen import primes<br />
3<br />
4 class IthPrime(threading.Thread):<br />
5 def __init__(self, i):<br />
6 threading.Thread.__init__(self)<br />
7 self.i = i<br />
8 def run(self):<br />
9 p = primes()<br />
10 for _ in range(self.i):<br />
11 e = p.next()<br />
12 self.ith_prime = e<br />
13 print "done %d, %d" % (self.i, e)<br />
14 def get_ith_prim():<br />
15 return self.ith_prime<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 286 / 326
Thread-Programmierung<br />
Thread-Programmierung in Python<br />
Wiederholung – Primzahlgenerator<br />
Generieren von Primzahlen<br />
• 2 und 3 sind Primzahlen<br />
• Ab da in Zweier-Schritten, wenn<br />
teilerfrei<br />
primegen.py<br />
1 def _teiler(x):<br />
2 return [t for t in range(2, x)<br />
3 if x%t == 0]<br />
4<br />
5 def primes():<br />
6 yield 2<br />
7 yield 3<br />
8 i = 5<br />
9 while True:<br />
10 if _teiler(i) == []:<br />
11 yield i<br />
12 i += 2<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 287 / 326
Thread-Programmierung<br />
Thread-Programmierung in Python<br />
Thread starten und auf Ende warten<br />
Thread starten<br />
• Instanz erzeugen und Methode start<br />
• Asynchron, kehrt sofort zurück<br />
• Seiteneffekt ist, dass Thread los läuft<br />
•<br />
6<br />
Thread beendet sobald run beendet ist t = IthPrime(i)<br />
7 t.start()<br />
Auf Ende warten<br />
8 print "compute in background"<br />
• Eventuell würde Haupt-Thread sich 9 t.join()<br />
beenden (ohne weitere Maßnahme) 10 s = "Die %d.te Primzahl ist %d"<br />
11 print s % (i, t.ith_prime)<br />
• Methode join auf Thread-Instanz<br />
12 print "ready"<br />
blockiert und wartet auf das Ende des<br />
Threads<br />
Zugriff auf Daten<br />
• Zuweisungen Python: atomar, sichtbar<br />
(nicht wie in Java)<br />
• Direkter Zugriff auf Attribute in<br />
Ordnung<br />
1<br />
2 if __name__ == ’__main__’:<br />
3 i = 3<br />
4 if sys.argv[1:]:<br />
5 i = int(sys.argv[1])<br />
$ python ith_prime.py 1000<br />
compute in background<br />
done 1000, 7919<br />
Die 1000.te Primzahl ist 7919<br />
ready<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 288 / 326
Thread-Programmierung<br />
Thread-Programmierung in Python<br />
Mehrere Threads<br />
Mehrere Threads<br />
• Beispiel 3 Threads für 1000.te,<br />
1001.te und 1002.te Primzahl<br />
• Jeweils auf Threads warten<br />
• Ausgabe der Strings (in richtiger<br />
Reihenfolge)<br />
Reihenfolge in den Threads<br />
• Nicht vorhersagbar<br />
• Reihenfolge der done Ausgabe<br />
variiert<br />
1 if __name__ == ’__main__’:<br />
2 i = int(sys.argv[1])<br />
3 ts = [IthPrime(j)<br />
4 for j in range(i, i+3)]<br />
5 for t in ts:<br />
6 t.start()<br />
7 for t in ts:<br />
8 t.join()<br />
9 for t in ts:<br />
10 s = "Die %d.te Primzahl ist %d"<br />
11 print s % (t.i, t.ith_prime)<br />
$ python ith_prime_mehrere.py 1000<br />
done 1000, 7919<br />
done 1002, 7933<br />
done 1001, 7927<br />
Die 1000.te Primzahl ist 7919<br />
Die 1001.te Primzahl ist 7927<br />
Die 1002.te Primzahl ist 7933<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 289 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Threads – Kontrolle Ablauf<br />
Unmöglich Thread von außen zu stoppen<br />
• Es kann keine Möglichkeit geben, die<br />
immer funktioniert<br />
• Anwendungsentwickler muss entsprechende<br />
Möglichkeiten vorsehen<br />
Ansatz<br />
• Methoden zum Setzen von Variablen<br />
• Periodische Überprüfung der<br />
Variablen<br />
• Synchronisation ok (in Python)<br />
• Ein Thread liest, anderer schreibt<br />
• Bool immer komplett geändert<br />
• Aktuelle Werte in CPython immer<br />
gleich sichtbar (nicht in Java)<br />
1 from threading import Thread<br />
2 from time import sleep<br />
3<br />
4 class Incer(Thread):<br />
5 def __init__(self):<br />
6 Thread.__init__(self)<br />
7 self.weiter = True<br />
8 def run(self):<br />
9 x = 0<br />
10 while self.weiter:<br />
11 x += 1<br />
12 sleep(1) # 1 Sekunde schlafen<br />
13 print "x", x<br />
14 def anhalten(self):<br />
15 self.weiter = False<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 290 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Threads– Kontrolle Ablauf, Verwendung<br />
Beispiel Ausgabe<br />
• isAlive, läuft Thread?<br />
• join verwenden<br />
1 from incer import Incer<br />
2 from time import sleep<br />
3<br />
4 inc = Incer()<br />
5 inc.start()<br />
6 sleep(3)<br />
7 inc.anhalten()<br />
8 print "Lebt?", inc.isAlive()<br />
9 inc.join()<br />
10 print "Lebt?", inc.isAlive()<br />
x 1<br />
x 2<br />
Lebt? True<br />
x 3<br />
Lebt? False<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 291 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Threads – Ende erreicht?<br />
Niemals aktiv warten!<br />
• CPU-Zeit mit Nichtstun/Warten<br />
verschwendet, hohe Last<br />
• Nie, nie, nie tun<br />
Thread.join ist ok<br />
• Wartet, dass Thread beendet wird<br />
• Aktuell laufender Thread hält,<br />
verschwendet aber keine<br />
Prozessorzeit<br />
Nachteil von Thread.join<br />
• Aktueller Thread läuft nicht weiter<br />
(aber das ist Intention)<br />
• Falls # was sinnvolles lange dauert,<br />
dann wird nicht gleich reagiert sobald<br />
der Thread zu Ende ist<br />
1 from incer import Incer<br />
2 from time import sleep<br />
3<br />
4 inc = Incer()<br />
5 # Thread beginnt zu laufen<br />
6 inc.start()<br />
7 while inc.isAlive(): # busy wait, boese<br />
8 pass<br />
9 # weiter nach Thread-Ende<br />
1 from incer import Incer<br />
2 from time import sleep<br />
3<br />
4 inc = Incer()<br />
5 inc.start()<br />
6 # was sinnvolles<br />
7 inc.join()<br />
8 # Ergebnis des Threads verwenden<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 292 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Aktion nach Ende Thread – Naja<br />
Ziel<br />
• Etwas nach Ende eines Threads tun<br />
• Direkt, wenn die Berechnung im<br />
Thread zu Ende ist<br />
Fragwürdige Umsetzung<br />
• Verarbeitung im Haupt-Thread<br />
• Warten bis Berechnungs-Thread am<br />
Ende<br />
Problem<br />
• Falls # was sinnvolles lange dauert<br />
• Keine sofortige Reaktion falls<br />
Berechnung zu Ende<br />
1000.te Primzahl ist 7919<br />
1 import threading, primegen<br />
2 class Langlaeufer(threading.Thread):<br />
3 def __init__(self, iteprim):<br />
4 threading.Thread.__init__(self)<br />
5 self.iteprim = iteprim<br />
6 def run(self):<br />
7 p = primegen.primes()<br />
8 for _ in range(self.iteprim):<br />
9 e = p.next()<br />
10 self.prim = e<br />
11 def get_prim(self):<br />
12 return self.prim<br />
13 if __name__ == ’__main__’:<br />
14 ite = 1000<br />
15 t = Langlaeufer(ite)<br />
16 t.start()<br />
17 # was anderes sinnvolles<br />
18 t.join()<br />
19 tup = (ite, t.get_prim())<br />
20 print "%d.te Primzahl ist %d" % tup<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 293 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Aktion nach Ende Thread – Besser<br />
Bessere Umsetzung<br />
• Verarbeitung noch im<br />
Berechnungs-Thread<br />
• Callback-Funktion mit übergeben<br />
Vorteile<br />
• Es wird sofort bei Ende der<br />
Berechnung mit dem<br />
Berechnungsergebnis weiter<br />
gearbeitet<br />
• Main-Thread wird nicht beansprucht<br />
• Durch Übergabe “Callback” bleibt<br />
Implementierung unabhängig<br />
1000.te Primzahl ist 7919<br />
1 import threading, primegen<br />
2 class Langlaeufer(threading.Thread):<br />
3 def __init__(self, itep, ende=None):<br />
4 threading.Thread.__init__(self)<br />
5 self.iteprim = itep<br />
6 self.am_ende = ende<br />
7 def run(self):<br />
8 p = primegen.primes()<br />
9 for _ in range(self.iteprim):<br />
10 e = p.next()<br />
11 self.prim = e<br />
12 self.am_ende(self.prim)<br />
13 if __name__ == ’__main__’:<br />
14 ite = 1000<br />
15 def print_prim(iteprim):<br />
16 tup = (ite, iteprim)<br />
17 print "%d.te Primzahl ist %d" % tup<br />
18 t = Langlaeufer(ite, print_prim)<br />
19 t.start()<br />
20 # was anderes sinnvolles<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 294 / 326
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Reihenfolgeproblem<br />
Thread-Ausführung ist nicht-deterministisch<br />
• Keine Aussage welcher Thread zuerst beendet wird möglich<br />
• Keine Aussage welcher Thread(Teil) vor/nach anderem Thread(Teil) ausgeführt<br />
• Keine Aussage wann welche Anweisung in einem Thread unterbrochen wird<br />
Problem bei gemeinsam geschriebenen (shared) Daten<br />
• Bei getrennt genutzten oder Nur-Lese-Daten kein Problem<br />
• Wann immer möglich Thread-lokale Daten verwenden, idealerweise keine shared<br />
Daten oder nur lesbare Daten<br />
• Falls shared Daten nur lesbar sind und bei gemeinsamer Verwaltung sicher initialisiert<br />
sind, keine Inkonsistenz möglich<br />
• Reihenfolge des Schreibens bei gemeinsamen Daten potenziell problematisch<br />
• Zusätzliche Ablauf-Fehler bei ansonsten “sequenziell korrektem” Programm möglich<br />
• Kritischer Wettlauf (race condition)<br />
Lösungsansatz<br />
• Kritische Sektionen identifizieren und synchronisieren<br />
• Nur ein Ausführungsstrang in kritischer Sektion (Sperren)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 295 / 326
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Kritischer Wettlauf – Beispiel Incer<br />
Globale Variable x<br />
• Initial 0<br />
• Durch zwei Threads um 1 erhöht<br />
Problem<br />
• x+=1 sind drei unterbrechbare<br />
Anweisungen<br />
• Lese (read/r) x in y<br />
• Berechne y = y + 1<br />
• Schreibe (write/w) y in x<br />
• Lesen und Schreiben der gleichen<br />
Variable x, Race condition<br />
• y unkritisch, thread-lokal, zwei Mal y<br />
y<br />
6<br />
7<br />
Thread-1<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
y=r(x)<br />
y+=1<br />
x<br />
0<br />
? 12 ?<br />
x<br />
6<br />
Thread-2<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
x+=1<br />
y=r(x)<br />
y+=1<br />
y<br />
6<br />
7<br />
Kritischer Wettlauf<br />
7<br />
x=w(y)<br />
y=w(y)<br />
7<br />
• Quasi gleichzeitiges Ausführen in<br />
kritischem Bereich<br />
Kritischer<br />
Bereich<br />
7<br />
statt 8<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 296 / 326
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Unsynchronisierter Incer in Python<br />
Incer<br />
• x ist globale Variable auf Modulebene,<br />
die mehrmals erhöht wird<br />
• Instanzvariable runs (thread-lokal), wie<br />
häufig wird x je Thread erhöht<br />
• In run jedes Threads das<br />
Inkrementieren jeweils runs mal<br />
Ausführen<br />
• Zwei Threads<br />
• 1 Million Mal erhöhen je Thread<br />
• Laufen lassen, Überraschung<br />
• Unvorhersagbares Verhalten<br />
• x meist < 2 Millionen<br />
• Falsch, Nebenläufigkeits-Bug<br />
Oooops 1488923 statt 2000000<br />
1 from threading import Thread<br />
2 x=0<br />
3 class Incer(Thread):<br />
4 def __init__(self, runs):<br />
5 Thread.__init__(self)<br />
6 self.runs = runs<br />
7 def run(self):<br />
8 global x<br />
9 for _ in xrange(self.runs):<br />
10 x += 1<br />
11 if __name__ == ’__main__’:<br />
12 runs = 10**6<br />
13 inc1, inc2 = Incer(runs), Incer(runs)<br />
14 inc1.start()<br />
15 inc2.start()<br />
16 inc1.join()<br />
17 inc2.join()<br />
18 if x != 2*runs:<br />
19 print "Oooops",x,"statt",2*runs<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 297 / 326
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Kritischer Bereich<br />
Kritischer Wettlauf<br />
• Potenzieller Fehler durch quasi-gleichzeitiges<br />
Ausführen von kritischen Bereichen<br />
Kritischer Bereich<br />
• Anweisungsfolge, mit zusammenhängendem Lesen<br />
und Schreiben auf geteilten Daten<br />
• Zusammengesetzte Aktionen wie zum Beispiel<br />
“check then act”<br />
• Synchronisation um sicherzustellen, dass immer nur<br />
ein Thread sich in einem kritischen Bereich befindet<br />
Beispiele für kritischen Bereich<br />
• x += 1, Lesen/ Schreiben gemeinsamer Variable<br />
• “check” (Warteschlange nicht leer?) “then act” (hole<br />
erstes Element der Warteschlange), nicht-leere<br />
Warteschlange nicht garantiert (durch anderen<br />
Thread zwischenzeitlich geleert)<br />
1 # Beginn kritischer Bereich<br />
2 x += 1<br />
3 # Ende kritischer Bereich<br />
1 # Beginn kritischer Bereich<br />
2 y = x<br />
3 y += 1<br />
4 x = y<br />
5 # Ende kritischer Bereich<br />
1 # Beginn kritischer Bereich<br />
2 if not queue.empty():<br />
3 v = queue.get_nowait()<br />
4 # Ende kritischer Bereich<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 298 / 326
Thread-Programmierung<br />
Sperren<br />
Synchronisation mit Sperren<br />
Kritischer Bereich: x+=1<br />
Sperr-Objekt<br />
• Bietet sichere Sperre, atomare<br />
Operation zur Sperrverwaltung<br />
• acquire: Belegt Sperre (Anfrage), falls<br />
Sperre schon belegt, wird aktuell<br />
6<br />
7<br />
Thread.__init__(self)<br />
self.runs = runs<br />
8 def run(self):<br />
anfragender Thread suspendiert<br />
9 global x<br />
(schlafen gelegt)<br />
10 for _ in xrange(self.runs):<br />
• release: Gibt belegte Sperre wieder 11 sperre.acquire() # Start sicher<br />
frei (sollte durch diesen Thread belegt 12 x += 1 # kritischer Bereich<br />
worden sein, sonst wird es schwierig<br />
zu durchschauen)<br />
13<br />
14<br />
sperre.release() # Ende sicher<br />
if __name__ == ’__main__’:<br />
15 runs = 10**6<br />
• Best-Practice: acquire/release-Block<br />
16 inc1, inc2 = Incer(runs), Incer(runs)<br />
umschließt kritischen Bereich, 11–13<br />
17 inc1.start(); inc2.start()<br />
gut, da alles gesichert ;-)<br />
1 from threading import Thread, Lock<br />
2 x = 0<br />
3 sperre = Lock() # Guard<br />
4 class Incer(Thread):<br />
5 def __init__(self, runs):<br />
18 inc1.join(); inc2.join()<br />
19 if x == 2*runs:<br />
20 print "gut, da alles gesichert ;-)"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 299 / 326
Thread-Programmierung<br />
Sperren<br />
Sperren ist aufwendig<br />
Sperren ist aufwendig<br />
• Unterstützung des Betriebssystems,<br />
der Hardware (spezielle Instruktionen)<br />
• Kontextwechsel bei Suspendierung<br />
des Threads durch belegte Sperre<br />
5<br />
6<br />
inc1, inc2 = Incer(runs), Incer(runs)<br />
inc1.start(); inc2.start()<br />
7 inc1.join(); inc2.join()<br />
• Beispiel, hohe Wahrscheinlichkeit<br />
8 if __name__ == ’__main__’:<br />
blockierter Bereich (hohe “Contention”)<br />
9 runs = 10**7<br />
• (eine Größenordnung langsamer)<br />
Best-Practice<br />
• Sperren so kurz und gezielt wie<br />
möglich, nur so lange wie nötig<br />
• Zugriff auf eine gemeinsame Variable<br />
immer mit derselben Sperre (dem<br />
Guard/Wächter)<br />
• Sperren kritischer Bereich für<br />
Korrektheit notwendig<br />
1 from incerunsync import Incer as UIncer<br />
2 from incermitlock import Incer as SIncer<br />
3 from timeit import default_timer as now<br />
4 def runit(Incer, runs):<br />
10 start = now()<br />
11 runit(UIncer, runs)<br />
12 t = now()-start<br />
13 print "Unsynced: %6.2f s" % t<br />
14 start = now()<br />
15 runit(SIncer, runs)<br />
16 t = now()-start<br />
17 print "Synced : %6.2f s" % t<br />
Unsynced: 1.67 s<br />
Synced : 14.97 s<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 300 / 326
Thread-Programmierung<br />
Sperren<br />
Sperren Lock und RLock<br />
Lock – Sperrobjekt, exklusiv<br />
• acquire(blocked=True), default<br />
• Sperre belegen wenn verfügbar und True zurück<br />
• Wenn belegt, Thread blockieren (schlafen legen)<br />
• acquire(blocked=False)<br />
• Sperre belegen wenn verfügbar und True zurück<br />
• Wenn Sperre schon belegt, dann False zurück<br />
• Erlaubt auf belegte Sperren zu reagieren<br />
• release()<br />
• Gibt belegtes Sperrobjekt frei<br />
• Ausnahme, falls Sperre nicht belegt<br />
RLock – Sperrobjekt, reentrant, wie Lock plus<br />
• Erlaubt verschachtelte acquire/release Aufrufe<br />
• Sonst acquire();acquire() Deadlock<br />
• Bei RLock wird nur ein Zähler erhöht<br />
• Verwendung: Sichere Methode in sicherer Methode<br />
• Verhalten wie in Java<br />
1 from threading import RLock<br />
2 sperre = RLock()<br />
3 class C(object):<br />
4 def a(self):<br />
5 sperre.acquire()<br />
6 print "methode a"<br />
7 self.b()<br />
8 sperre.release()<br />
9 def b(self):<br />
10 sperre.acquire()<br />
11 print "methode b"<br />
12 sperre.release()<br />
13<br />
14 if __name__ == ’__main__’:<br />
15 c = C()<br />
16 c.a()<br />
methode a<br />
methode b<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 301 / 326
Thread-Programmierung<br />
Sperren<br />
Sichere Objekte, Monitor<br />
Bisher: Konventionen<br />
• Globale Objekte x und sperre<br />
• Konvention, dass jeder, der auf x<br />
zugreift diesen Bereich mit sperre<br />
sperren muss<br />
• Fehleranfällig (nicht perfekter<br />
Entwickler)<br />
Besser: Kapselung in sicherem Objekt<br />
• Eigene Klasse mit sicheren<br />
Zugriffsmethoden<br />
• synchronized in Java<br />
• Lokales Sperrobjekt in Instanz der<br />
Klasse<br />
• In Java meist Instanzobjekt selbst<br />
• Typisches Pattern bei Methode value,<br />
sonst release schwierig<br />
counter.py<br />
1 from threading import RLock<br />
2 class Counter(object):<br />
3 def __init__(self):<br />
4 self.count = 0<br />
5 self._lock = RLock()<br />
6 def inc(self):<br />
7 self._lock.acquire()<br />
8 self.count += 1<br />
9 self._lock.release()<br />
10 def value(self):<br />
11 self._lock.acquire()<br />
12 ret = self.count<br />
13 self._lock.release()<br />
14 return ret<br />
Counter ist ein Monitor<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 302 / 326
Thread-Programmierung<br />
Sperren<br />
Sichere Objekte, Monitor, Verwendung<br />
Incer mit Counter<br />
• Counter als sicheres Objekt<br />
• Instanz von Counter zum Zählen<br />
Vorteile<br />
• Verwender (Entwickler) von Counter<br />
muss keine Sperren verwenden<br />
• Entwickler kann keine Sperren<br />
vergessen<br />
RLock teurer in Python,<br />
Beispiel 2,5 Mal langsamer<br />
gut, da alles gesichert ;-)<br />
1 from threading import Thread<br />
2 from counter import Counter<br />
3 class Incer(Thread):<br />
4 def __init__(self, counter, runs):<br />
5 Thread.__init__(self)<br />
6 self.counter = counter<br />
7 self.runs = runs<br />
8 def run(self):<br />
9 for _ in xrange(self.runs):<br />
10 self.counter.inc()<br />
11 if __name__ == ’__main__’:<br />
12 runs = 10**6<br />
13 counter = Counter()<br />
14 inc1 = Incer(counter, runs)<br />
15 inc2 = Incer(counter, runs)<br />
16 inc1.start(); inc2.start()<br />
17 inc1.join(); inc2.join()<br />
18 if 2*runs == counter.value():<br />
19 print "gut, da alles gesichert ;-)"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 303 / 326
Thread-Programmierung<br />
Sperren<br />
Das with-Statement<br />
with-Statement, ein Block<br />
• Default-Operationen bei Eintritt<br />
__enter__ Austritt __exit__ aus Block<br />
• Beispiele: Bei Datei öffnen/schließen,<br />
bei Sperre belegen/freigeben<br />
• Seit Python 2.6<br />
Beispiel: Counter-Objekt aufgeräumter<br />
• Ausführung, hohe Contention<br />
1 from threading import Thread<br />
2 from counterwith import Counter<br />
3 from IncerCounter import Incer<br />
4 no_incers, incruns = 300, 1000<br />
5 counter = Counter()<br />
6 incers = [Incer(counter, incruns) for _ in range(no_incers)]<br />
7 for incer in incers: incer.start()<br />
8 for incer in incers: incer.join() # barrier<br />
1 from threading import RLock<br />
2 class Counter(object):<br />
3 def __init__(self):<br />
4 self.count = 0<br />
5 self._lock = RLock()<br />
6 def inc(self):<br />
7 with self._lock:<br />
8 self.count += 1<br />
9 def value(self):<br />
10 with self._lock:<br />
11 return self.count<br />
got 300000 expected 300000<br />
9 print "got", counter.value(), "expected", no_incers*incruns<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 304 / 326
Thread-Programmierung<br />
Sperren<br />
Zwei sichere Objekte kombiniert nicht unbedingt sicher<br />
Zwei sichere Objekte<br />
• Zwei Counter<br />
• Jeder Counter für sich sicher<br />
• Egal wie viele Threads gleichzeitig<br />
erhöhen, jede Erhöhung wird gezählt<br />
• Neuer kritischer Bereich wenn beide<br />
Counter immer gleichzeitig erhöht<br />
werden sollen<br />
Sichern<br />
• Neue Sperre, während Erhöhung<br />
stattfindet<br />
• Alte Sperren jetzt nutzlos, nur noch<br />
Aufwand<br />
47786 Oopps von 100000 Tests: 47%<br />
1 from threading import Thread, RLock<br />
2 from counter import Counter<br />
3 c1, c2 = Counter(), Counter()<br />
4 class ZweiCounter(Thread):<br />
5 def run(self):<br />
6 for _ in range(10**5):<br />
7 c1.inc(); c2.inc()<br />
8 class Peeker(Thread):<br />
9 def run(self):<br />
10 tests, oops = 0, 0<br />
11 for _ in range(10**5):<br />
12 tests += 1<br />
13 if c1.value() != c2.value():<br />
14 oops += 1<br />
15 s = "%d Oopps von %d Tests: %d%%"<br />
16 prozent = oops*100./tests<br />
17 print s % (oops, tests, prozent)<br />
18 zc, p = ZweiCounter(), Peeker()<br />
19 zc.start(); p.start()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 305 / 326
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Safety, Sicherheit<br />
• Vermeide Fehler, die durch Lese/Schreib-Zugriff verschiedener Threads auf<br />
gemeinsame Variable entstehen (Reihenfolge)<br />
• Kein Problem, falls keine gemeinsamen Variablem oder Nur-Lese Variablen<br />
• Ansonsten Einsatz von Sperren<br />
Liveness, Fortschritt<br />
• Irgend etwas sinnvolles wird irgendwann passieren<br />
• Beispiele: Deadlock (wie in DBMS) oder Starvation (Verhungern)<br />
• Schwer zu erkennen und zu beseitigen, sporadisches Auftreten<br />
Performance<br />
• Mehrkosten zur Laufzeit (Ressourcen/Speicher je Thread, Kontextwechsel,<br />
Synchronisation)<br />
• Wenige Threads (bei Berechnung nicht deutlich mehr als Kerne)<br />
• Wenige und kurze Sperren<br />
• Anpassen Algorithmen an verteilte Umgebung<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 306 / 326
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Deadlock<br />
Deadlock, Verklemmung<br />
• Threads warten auf Freigabe von<br />
Ressourcen, die nicht erfolgt<br />
• Kein Fortschritt mehr, unendliches<br />
Warten<br />
• Verschiedene Szenarios möglich<br />
Zweimal sperren auf einer Sperre<br />
10 with self._lock:<br />
• In einem Thread Sperre erhalten<br />
11 self.mach()<br />
• Nochmal Sperre holen, sperrt auf ewig12 def run(self):<br />
Posix Sperren<br />
• Sperren müssen freigegeben werden,<br />
auch wenn derselbe Thread die<br />
Sperre anfordert<br />
• Java-Verhalten mit RLock, dann läuft<br />
Beispiel durch<br />
1 from threading import Thread, Lock<br />
2 class Deadlock(Thread):<br />
3 def __init__(self):<br />
4 Thread.__init__(self)<br />
5 self._lock = Lock()<br />
6 def mach(self):<br />
7 with self._lock:<br />
8 pass<br />
9 def do(self):<br />
13 self.do()<br />
14 print "fertig"<br />
15 d = Deadlock()<br />
16 d.start()<br />
17 d.join()<br />
18 # haengt, nie fertig<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 307 / 326
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Deadlock – Verschränkte Sperren<br />
Verschränkt Sperren auf zwei Sperren<br />
• Ein Thread macht erst l1, dann l2<br />
• Ein Anderer erst l2, dann l1<br />
• Deadlock, sobald do und mach<br />
verschränkt ausgeführt werden<br />
Lösung<br />
• mach: l1 gesperrt, Threadwechsel<br />
• do: l2 gesperrt, warte auf l1<br />
• mach: warte auf l2<br />
• Sperrordnung, wie bei DBMS<br />
• Zum Beispiel l1 immer vor l2<br />
d1<br />
l1<br />
l2<br />
d2<br />
deadlockverschr.py<br />
1 from threading import Thread, Lock<br />
2 l1, l2 = Lock(), Lock()<br />
3 class Deadlock(Thread):<br />
4 def __init__(self, doDo=True):<br />
5 Thread.__init__(self)<br />
6 self.d = doDo<br />
7 def mach(self):<br />
8 with l1:<br />
9 with l2:<br />
10 print "mach"<br />
11 def do(self):<br />
12 with l2:<br />
13 with l1:<br />
14 print "do"<br />
15 def run(self):<br />
16 f = self.do if self.d else self.mac<br />
17 for _ in range(10**4): f()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 308 / 326
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Deadlock – Verschränkte Sperren, Ausführung<br />
Verwendung<br />
• Zwei Instanzen<br />
• Eine mit Sperrreihenfolge<br />
l1, dann l2<br />
• Eine mit Sperrreihenfolge<br />
l2, dann l1<br />
• Meist kein Ende sondern Deadlock,<br />
verschränktes Sperren<br />
1 from deadlockverschr import Deadlock<br />
2<br />
3 d1 = Deadlock(True) # do<br />
4 d2 = Deadlock(False) # mach<br />
5 d1.start()<br />
6 d2.start()<br />
7 d1.join()<br />
8 d2.join()<br />
9<br />
10 # passiert wahrscheinlich nie<br />
11 print "Ganz Fertig"<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 309 / 326
Thread-Programmierung<br />
Besonderheiten bei Threads in Python<br />
Besonderheiten bei Threads in Python<br />
GIL in CPython-Implementierung (und PyPy)<br />
• Global Interpreter Lock (GIL)<br />
• Nur ein Python-Thread kann zu einem Zeitpunkt auf Python-Strukturen zugreifen<br />
• Nur ein Python-Thread läuft zu jedem Zeitpunkt<br />
• Keine effektive Nutzung von Mehrkernsystemen möglich<br />
• Trotzdem sinnvolle Nutzung von Wartezeiten bei Langläufern<br />
• GIL wird bei Warten auf externe Ereignisse (IO) losgelassen<br />
• Thread-Scheduling von Laufzeitumgebung<br />
• Alle 100 Bytecode-Anweisungen<br />
• sys.getcheckinterval, sys.setcheckinterval<br />
• Alternative ab Python 2.6: multithreading<br />
• Arbeitet mit mehreren Python-Prozessen<br />
• Effektive Nutzung von Mehrkernsystemen möglich<br />
Basiert auf thread-Modul<br />
• Low-Level API, für die meisten Umgebungen verwendbar<br />
• Empfehlung: threading verwenden, Wissen für Java-Programmierung verwendbar<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 310 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Producer/Consumer<br />
Situation<br />
• Ein Produzent erzeugt Werte<br />
• Ein Konsument verwendet Werte<br />
• Beide können unabhängig voneinander laufen<br />
• Problem: Konsument muss warten, bis Produzent<br />
fertig; Produzent muss warten, bis Konsument fertig<br />
Warteschlange<br />
• Entkopplung von Produzent und Konsument<br />
• Produzent legt fertige Werte in Warteschlange<br />
• Konsument holt Werte aus der Warteschlange<br />
• Warteschlange ist gemeinsames Objekt, Zugriffe<br />
müssen synchronisiert werden<br />
• Bei leerer Warteschlange muss Konsument warten<br />
• Bei voller Warteschlange (begrenzte Größe) muss<br />
Produzent warten<br />
• Einfügen/Entfernen nur einer gleichzeitig<br />
Produzent<br />
Konsument<br />
Warteschlange<br />
flexible<br />
Größe<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 311 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Producer<br />
Aufgabe<br />
• Erzeuge Zahlen von 1 bis anz<br />
Klasse Producer<br />
• Ein Thread<br />
Gemeinsame Objekte<br />
• Warteschlange, queue<br />
• Sperre auf Warteschlange, qlock<br />
Ausführung, run<br />
• Immer kurz warten<br />
• Zugriff auf Warteschlange als<br />
kritischer Bereich mit Sperren<br />
umschließen<br />
• Jeweils nächstes Element einfügen<br />
producer.py<br />
1 from threading import Thread<br />
2 import time, random<br />
3 class Producer(Thread):<br />
4 def __init__(self, anz, queue, qlock):<br />
5 Thread.__init__(self)<br />
6 self.anz = anz # endlich viele<br />
7 self.queue = queue<br />
8 self.qlock = qlock<br />
9 def run(self):<br />
10 for i in range(1, self.anz+1):<br />
11 # etwas Zeit lassen...<br />
12 time.sleep(random.random()/100.)<br />
13 with self.qlock:<br />
14 self.queue.insert(0, i)<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 312 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Consumer<br />
Aufgabe<br />
• Alle Elemente aus<br />
Warteschlange aufsummieren<br />
Klasse Consumer, ein Thread<br />
Gemeinsame Objekte<br />
• Warteschlange, queue<br />
• Sperre auf Warteschl., qlock<br />
Ausführung, run<br />
• Solange noch was kommen<br />
kann oder noch was da ist<br />
• Entferne nächstes Element von<br />
queue und summiere es auf<br />
• Falls kein Element in queue,<br />
ein bisschen warten<br />
consumer.py<br />
1 from threading import Thread<br />
2 import time, random<br />
3 class Consumer(Thread):<br />
4 def __init__(self, queue, qlock):<br />
5 Thread.__init__(self)<br />
6 self.queue, self.qlock = queue, qlock<br />
7 self.summe, self.misses = 0,0<br />
8 self.done = False # soll stoppen<br />
9 def run(self):<br />
10 while not self.done or self.queue:<br />
11 value = None<br />
12 with self.qlock:<br />
13 if self.queue:<br />
14 value = self.queue.pop()<br />
15 if value:<br />
16 self.summe += value<br />
17 else:<br />
18 time.sleep(random.random()/100.)<br />
19 self.misses += 1<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 313 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Producer / Consumer<br />
1 from producer import Producer<br />
Gemeinsame Objekte anlegen<br />
2 from consumer import Consumer<br />
• Warteschlange, list<br />
3 from threading import Lock<br />
• Warteschlangensperre, Lock<br />
4<br />
5 anz = 100<br />
Producer/Consumer erzeugen, starten<br />
6 queue = []<br />
• Erste beide erzeugen<br />
7 qlock = Lock()<br />
•<br />
8<br />
Dann beide starten (fast gleichzeitig)<br />
9 producer = Producer(anz, queue, qlock)<br />
Producer/Consumer join<br />
10 consumer = Consumer(queue, qlock)<br />
• Auf Ende des Produzenten warten, nur11<br />
anz viele werden erzeugt<br />
12 producer.start()<br />
13 consumer.start()<br />
• Dem Konsumenten mitteilen, dass<br />
14<br />
keine weiteren Werte kommen werden<br />
15 producer.join()<br />
• Auf Ende Consumer warten<br />
16 consumer.done = True<br />
Ergebnis ist fertig<br />
misses: 91<br />
17 consumer.join()<br />
18<br />
19 print "misses:", consumer.misses<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 314 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Performance Problem<br />
Producer produziert zu schnell<br />
• Sehr viel Speicher wird verschwendet<br />
• Lösung: Begrenzte Warteschlange<br />
Warteschlange voll oder leer<br />
• Warteschlange leer: Konsument findet keinen Wert<br />
• Warteschlange voll: Produzent generiert keinen Wert<br />
• Aber in beiden Fällen wir Schleife durchlaufen<br />
• Rechenzeit wird verbraucht ohne Effekt<br />
(Teil-)Lösung bisher<br />
• Wenn Extremsituation eintritt, dann ein bisschen schlafen<br />
• Ist aber nur raten/flicken<br />
Lösungsansatz<br />
• Thread schlafen legen und wieder aufwecken<br />
• Wenn Warteschlange leer, dann soll Konsument schlafen<br />
• Wenn Element eingefügt wird, dann soll Konsument geweckt werden<br />
• Spezielle Konstrukte für Schlafen/Aufwecken sind wait/notify<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 315 / 326
Thread-Programmierung<br />
wait/notify<br />
wait/notify<br />
Condition<br />
• Klasse von threading<br />
• Hält intern Sperre, kann sie auch<br />
beim Initialisieren bekommen<br />
• Implementiert Lock-Interface,<br />
acquire, release<br />
c.acquire()<br />
erzeuge()<br />
c.notify()<br />
c.release()<br />
c = Condition()<br />
c.acquire()<br />
while nixda():<br />
wait()<br />
verwende()<br />
c.release()<br />
• Weitere Methoden wait, notify, notifyAll<br />
wait()<br />
• Lässt Sperre los (Sperre muss belegt sein), legt aktuellen Thread schlafen<br />
• Weiterlaufen erst, wenn notify oder notifyAll auf Condition gerufen wurde<br />
notify()<br />
• Sperre muss belegt sein<br />
• Informiert einen der wartenden Threads, dass es weiter gehen könnte<br />
• Programmierer lässt danach Sperre meist wieder los (release)<br />
notifyAll(): wie notify, nur werden alle Threads informiert<br />
Jedes Java Objekt implementiert wait, notify, notifyAll<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 316 / 326
Thread-Programmierung<br />
wait/notify<br />
Producer mit wait/notify<br />
Aufgabe<br />
• Produzent ohne aktives Warten<br />
Gemeinsame Objekte<br />
• Warteschlange queue als Liste<br />
• Condition cond als Sperre<br />
Producer, Thread<br />
• Von außen abbrechbar mit self.do<br />
• Falls Element in queue, dann keins<br />
mehr produzieren; de facto<br />
Warteschlange mit Länge 1<br />
• Falls ein Element drin ist, dann wird<br />
ein auf cond wartender Thread<br />
geweckt (nach release)<br />
• Es wird langsamer produziert<br />
• Am Ende des Threads werden alle<br />
wartenden Threads geweckt<br />
produceroaw.py<br />
1 from threading import Thread<br />
2 import time, random<br />
3 class Producer(Thread):<br />
4 def __init__(self, queue, cond):<br />
5 Thread.__init__(self)<br />
6 self.do = True<br />
7 self.queue = queue<br />
8 self.cond = cond<br />
9 def run(self):<br />
10 i=0<br />
11 while self.do:<br />
12 with self.cond:<br />
13 if not self.queue:<br />
14 self.queue.append(i)<br />
15 self.cond.notify()<br />
16 i += 1<br />
17 # time.sleep(0.01)<br />
18 with self.cond:<br />
19 self.cond.notifyAll()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 317 / 326
Thread-Programmierung<br />
wait/notify<br />
Consumer mit wait/notify<br />
Aufgabe<br />
• Schlafen legen, falls nichts<br />
verfügbar<br />
Gemeinsame Objekte<br />
• Warteschlange queue als Liste<br />
• Condition cond als Sperre<br />
Consumer, Thread<br />
• Wenn queue leer, dann schlafen<br />
mit wait<br />
• Schlafen immer in<br />
while-Schleife<br />
• Nach Aufwecken in gesperrtem<br />
Zustand<br />
consumeroaw.py<br />
1 from threading import Thread<br />
2 class Consumer(Thread):<br />
3 def __init__(self, queue, cond, id):<br />
4 Thread.__init__(self)<br />
5 self.do, self.id = True, id<br />
6 self.queue, self.cond = queue, cond<br />
7 def run(self):<br />
8 summe = 0<br />
9 while self.do:<br />
10 self.cond.acquire()<br />
11 while not self.queue and self.do:<br />
12 self.cond.wait()<br />
13 value = None<br />
14 if self.queue:<br />
15 value = self.queue.pop()<br />
16 self.cond.release()<br />
17 if value: summe += value<br />
18 msg = "done %d %6d" % (self.id, summe)<br />
19 print msg<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 318 / 326
Thread-Programmierung<br />
wait/notify<br />
Producer/Consumer mit wait/notify<br />
Aufgabe<br />
• Ein Produzent<br />
• Zwei Konsumenten, jeder liest<br />
• Keine Garantie, dass abwechselnd<br />
gelesen wird<br />
• Verhungern (Starvation) möglich<br />
Anmerkungen<br />
• notifyAll bei Producer, damit beide<br />
Konsumenten wach werden am Ende<br />
• Ergebnis bei jedem Durchlauf anders<br />
• Wie viele Zahlen insgesamt addiert<br />
• Wie auf Konsumenten aufgeteilt<br />
• Es ist möglich, dass Zahlen ignoriert<br />
werden beim Generieren<br />
done 1 740240716<br />
done 2 753020403<br />
1 from produceroaw import Producer<br />
2 from consumeroaw import Consumer<br />
3 from threading import Condition<br />
4 import time<br />
5<br />
6 queue = []<br />
7 cond = Condition()<br />
8 producer = Producer(queue, cond)<br />
9 c1 = Consumer(queue, cond, 1)<br />
10 c2 = Consumer(queue, cond, 2)<br />
11 producer.start()<br />
12 c1.start(); c2.start()<br />
13<br />
14 time.sleep(2) # 2 Sek. schlafen<br />
15<br />
16 producer.do = False<br />
17 c1.do, c2.do = False, False<br />
18 c1.join(); c2.join()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 319 / 326
Thread-Programmierung<br />
Spezielle Datentypen für Threading<br />
Spezieller Warteschlangen-Datentyp<br />
Producer/Consumer<br />
• Typisches Pattern bei nebenläufigem <strong>Programmieren</strong><br />
• Zentrale Datenstruktur ist Warteschlange<br />
• Umgeben von Synchronisations- und Warte-Idiomen<br />
Idee – spezielle Queue als vorgefertigter Datentyp<br />
• Sicheres Objekt<br />
• Sperre in Datentyp eingebaut<br />
• Automatisches Sperren bei Einfügen, Holen und Löschen<br />
• Warte-Idiome integriert, automatisch schlafen legen<br />
• Blockierender Zugriff beim Holen, falls noch nichts da<br />
• Blockierender Zugriff beim Einfügen, falls Warteschlange voll<br />
• Optional Pollen zum Zugriff<br />
• Nicht blockierend, Ausnahme, falls voll/leer<br />
• Achtung! Nicht falsch verwenden (Check then act)<br />
Ergebnis: Einfacheres Producer/Consumer Pattern<br />
put_nowait put<br />
Wenn<br />
voll<br />
Queue<br />
Wenn<br />
leer<br />
get_nowait get<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 320 / 326
Thread-Programmierung<br />
Spezielle Datentypen für Threading<br />
Queue<br />
Datenstruktur für Thread-Prog.<br />
• Klasse Queue im Modul Queue<br />
• Warteschlange für konkurrierenden<br />
Zugriff<br />
• Schreiber und Leser<br />
Queue<br />
• put(e)/get()<br />
• Schlüsselwortparameter block=True,<br />
default blockierender Zugriff<br />
• Schlüsselwortparameter<br />
timeout=, default None (ewig),<br />
Maximal Sekunden warten bis<br />
Ausnahme<br />
Wenn möglich dedizierte<br />
Datenstrukturen/Bibliotheken verwenden<br />
consumerqueue.py<br />
1 from threading import Thread<br />
2 from Queue import Empty<br />
3 class Consumer(Thread):<br />
4 def __init__(self, queue, id):<br />
5 Thread.__init__(self)<br />
6 self.do, self.id = True, id<br />
7 self.queue = queue<br />
8 def run(self):<br />
9 summe = 0<br />
10 while self.do:<br />
11 try: # 1 Sek. Timeout<br />
12 val = self.queue.get(True,1)<br />
13 summe += val<br />
14 except Empty:<br />
15 pass<br />
16 msg = "done %d %6d"<br />
17 print msg % (self.id, summe)<br />
• In Java java.util.concurrent<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 321 / 326
Thread-Programmierung<br />
Spezielle Datentypen für Threading<br />
Consumer/Producer mit Queue<br />
producerqueue.py<br />
1 from threading import Thread<br />
2 class Producer(Thread):<br />
3 def __init__(self, queue):<br />
4 Thread.__init__(self)<br />
5 self.do = True<br />
6 self.queue = queue<br />
7 def run(self):<br />
8 i=0<br />
9 while self.do:<br />
0 self.queue.put(i)<br />
1 i += 1<br />
1 from consumerqueue import Consumer<br />
2 from producerqueue import Producer<br />
3 from Queue import Queue<br />
4 import time<br />
5<br />
6 queue = Queue()<br />
7 p = Producer(queue)<br />
8 c1 = Consumer(queue, 1)<br />
9 c2 = Consumer(queue, 2)<br />
10 p.start();<br />
11 c1.start(); c2.start()<br />
12<br />
13 time.sleep(2)<br />
done 2 15994664301<br />
done 1 14952448204<br />
• Es geht nichts verloren<br />
• Effizienter<br />
14<br />
15 p.do = False<br />
16 c1.do, c2.do = False, False<br />
17<br />
18 c1.join(); c2.join()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 322 / 326
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Arbeits-Threads, Worker-Threads<br />
Parallelisierung<br />
• Serialisierung, Hintereinanderausführung, ein Thread<br />
• Parallelisierung: Ein Thread per Aufgabe (Task)<br />
• Problem: Zu extrem, zu viele Threads gleichzeitig, zu<br />
viel Overhead (Kontextwechsel)<br />
Ziel<br />
• Parallelisierung mit wenigen Threads, Worker<br />
• Ein Thread übernimmt mehrere Aufgaben<br />
• Auslastung der wenigen Worker-Threads, Auslastung<br />
des Gesamtsystems, wenig Overhead<br />
Umsetzung<br />
• Warteschlange (Queue) mit Arbeitsaufträgen<br />
• Jeder Thread holt sich (threadsicher) Aufträge und<br />
arbeitet diese ab<br />
• Ohne Arbeit schlafen oder beenden<br />
jetzt<br />
Worker<br />
Thread<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 323 / 326
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Worker Thread zum Addieren / 1<br />
Thread-Verwaltung<br />
• Klassenvariable counter, ein Monitor<br />
zur Thread-ID Verwaltung<br />
• Thread-IDs zwischen 1 und max.<br />
Anzahl Threads<br />
Idee<br />
• Erster Thread (id==1) läuft am<br />
längsten<br />
• Sobald irgendein anderer Thread eine<br />
leere Warteschlange trifft, wird dieser<br />
Thread beendet; es ist ja weniger zu<br />
tun<br />
• Erster Thread läuft aber noch weiter<br />
worker.py<br />
1 from threading import Thread<br />
2 from counterext import Counter<br />
3 from Queue import Empty<br />
4<br />
5 class Worker(Thread):<br />
6<br />
7 count = Counter()<br />
8<br />
9 def __init__(self, queue):<br />
10 Thread.__init__(self)<br />
11 self.queue = queue<br />
12 self.id = Worker.count.inc()<br />
13<br />
14 def run(self):<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 324 / 326
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Worker Thread zum Addieren / 2<br />
Umsetzung – Schleife<br />
• Schleife, beendet Threads mit<br />
hoher ID, nie 1<br />
• Hole erst v1, dann v2<br />
• Holen klappt nicht? Beenden!<br />
• Nur wenn id != 1<br />
• v1 zurück wenn v2 nicht klappt<br />
• Holen klappt? Summiere und<br />
Zahl wieder in Warteschlange<br />
Umsetzung – Beenden<br />
• Zähler wie viele Threads am<br />
Ende erniedrigen<br />
1 while Worker.count.value() >= self.id:<br />
2 v1, v2 = None, None<br />
3 try:<br />
4 v1 = self.queue.get(timeout=.1)<br />
5 except Empty:<br />
6 if self.id > 1: break<br />
7 continue<br />
8 try:<br />
9 v2 = self.queue.get(timeout=.1)<br />
10 except Empty:<br />
11 if (self.id > 1 or<br />
12 self.id==self.count.value()==1):<br />
13 if self.queue.empty():<br />
14 self.queue.put(v1)<br />
15 break<br />
16<br />
• self.queue.put(v1)<br />
Noch ein Element, noch ein<br />
17 continue<br />
Thread (id==1) und keine Arbeit<br />
18 v = v1 + v2<br />
mehr? Ganz fertig, beende auch<br />
19 self.queue.put(v)<br />
letzten Thread<br />
20 Worker.count.dec()<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 325 / 326
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Worker Thread zum Addieren – Verwendung<br />
Verwendung<br />
• Zu addierende Zahlen in queue<br />
• Alle Worker starten, dann warten<br />
• Interessant ist eigentlich nur der mit<br />
id=1, da der sich als Letztes beendet<br />
Kein gutes Beispiel<br />
• Aufwand je Task zu gering (Addition)<br />
• Wohl zu viele Threads für reine<br />
Berechnung (ohne I/O)<br />
• Keine Nutzung von vielen Kernen mit<br />
CPython<br />
Besseres Beispiel nächstes Semester<br />
• Servlet Engine, Thread-Pool<br />
• Web-Request (I/O) im Worker-Thread<br />
1 from worker import Worker<br />
2 from Queue import Queue<br />
3 anzworker, bis = 100, 10**5<br />
4 queue = Queue()<br />
5 for ele in xrange(1, bis+1):<br />
6 queue.put(ele)<br />
7 workers = []<br />
8 for _ in xrange(anzworker):<br />
9 workers.append(Worker(queue))<br />
10 for worker in workers:<br />
11 worker.start()<br />
12 for worker in workers:<br />
13 worker.join()<br />
14 summe = queue.get()<br />
15 print "Summe ist %d" % summe<br />
16 summe = sum(range(1, bis+1))<br />
17 print "Summe sollte sein %d" % summe<br />
Summe ist 5000050000<br />
Summe sollte sein 5000050000<br />
Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 326 / 326