4 in 1 - Medieninformatik - Hochschule RheinMain
4 in 1 - Medieninformatik - Hochschule RheinMain
4 in 1 - Medieninformatik - Hochschule RheinMain
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
Organisatorisches<br />
Organisatorisches<br />
Programmieren 3<br />
Programmieren <strong>in</strong> C und Python<br />
Prof. Dr. Peter Barth<br />
<strong>Hochschule</strong> Rhe<strong>in</strong>Ma<strong>in</strong><br />
Fachbereich Design Informatik Medien<br />
Medien<strong>in</strong>formatik<br />
29. Januar 2013<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 />
• Onl<strong>in</strong>e-Test C<br />
• Onl<strong>in</strong>e-Test Python<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 1 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 2 / 326<br />
Bewertung Praktikum<br />
Organisatorisches<br />
Ziele der Veranstaltung<br />
Organisatorisches<br />
Erreichbar<br />
• Onl<strong>in</strong>e-Test C<br />
• Onl<strong>in</strong>e-Test Python<br />
• Bonus beide Tests > 3 Punkte<br />
Bestanden<br />
• M<strong>in</strong>destens 6 Punkte<br />
• Bis 9 Punkte ausreichend<br />
Ke<strong>in</strong>e Wiederholung der Onl<strong>in</strong>e-Tests<br />
21 Punkte<br />
9 Punkte<br />
9 Punkte<br />
3 Punkte<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 Programmieren/Thread<strong>in</strong>g<br />
• Sprachebenen höhere Abstraktion und masch<strong>in</strong>ennah<br />
• E<strong>in</strong>satz und Nutzen passender Bibliotheken<br />
Umgang mit praxisrelevanten Sprachen <strong>in</strong> typischer Umgebung<br />
• Masch<strong>in</strong>ennahes Programmieren<br />
mit C<br />
• Höheres Programmieren/Skripten<br />
mit Python<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 3 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 4 / 326
Organisatorisches<br />
Organisatorisches<br />
Masch<strong>in</strong>ennahe Sprachen – C<br />
Ausdrucksstarke höhere Sprachen – Python<br />
C, Ansi C<br />
• Masch<strong>in</strong>ennahe 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 />
• Po<strong>in</strong>ter und Speicherverwaltung<br />
• Zeichenkettenverarbeitung<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 5 / 326<br />
Python<br />
• Skriptsprache<br />
• Anwendungsentwicklung<br />
• E<strong>in</strong>fach Quellcode zu erstellen,<br />
zu lesen, zu warten<br />
• Interaktiv, viele IDEs<br />
• Integration verschiedener Sprachparadigmen,<br />
E<strong>in</strong>satz nach Bedarf/Eleganz<br />
• Imperativ<br />
• Objekt-orientiert<br />
• Funktional<br />
• E<strong>in</strong>satz von Bibliotheken: GUI, reguläre Ausdrücke, . . .<br />
Inhalt<br />
• E<strong>in</strong>gebaute mächtige Datentypen und Kontrollstrukturen<br />
• Funktionales Programmieren und Generatoren<br />
• Module und Klassen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 6 / 326<br />
Thread-Programmierung<br />
Organisatorisches<br />
Literatur<br />
Organisatorisches<br />
Nebenläufiges Programmieren / Thread-Programmierung<br />
• Mehrere Ausführungsstränge gleichzeitig<br />
<strong>in</strong>nerhalb e<strong>in</strong>es Prozesses e<strong>in</strong>es Anwendungsprogramms<br />
• Zeit s<strong>in</strong>nvoll 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 />
C<br />
• C als erste Programmiersprache, Dausmann,<br />
Bröckl, Goll[Onl<strong>in</strong>e verfügbar]<br />
• Programmieren <strong>in</strong> C, (ANSI C),<br />
Brian W. Kernighan, Dennis M. Ritchie<br />
• http://openbook.galileocomput<strong>in</strong>g.de<br />
Python<br />
/c_von_a_bis_z/<br />
• http://www.python.org/doc<br />
• E<strong>in</strong>führung <strong>in</strong> Python, Mark Lutz und<br />
David Ascher, O’Reilly, 2. Auflage<br />
• Python Script<strong>in</strong>g for Computational Science,<br />
Langtangen, Spr<strong>in</strong>ger<br />
Thread<strong>in</strong>g<br />
• Concurrent Programm<strong>in</strong>g <strong>in</strong> Java, Doug Lea<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 7 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 8 / 326
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Die Programmiersprache C<br />
Seit 1971 für Systemprogrammierung<br />
Verbreitung von C<br />
Weltweit ist C die meist verwendete Programmiersprache<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 />
• Masch<strong>in</strong>ennah, 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 Programm<strong>in</strong>g Language”<br />
89: Standardisierung, ANSI-C (Sprache, Bibliotheken),<br />
Überarbeitung C90, heute weit verbreitet<br />
99: C99, E<strong>in</strong>flüsse C++, noch nicht weit verbreitet<br />
Verwendung<br />
• Systementwicklung, „portabler Assembler“<br />
• Betriebssysteme (z.B. Unix, L<strong>in</strong>ux), Tools (z.B. Shell, gtk)<br />
• Programmiersprachen (z.B. Java, Python, ...)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 9 / 326<br />
The C Programm<strong>in</strong>g Language<br />
• Klassisches Buch<br />
• Übersetzt <strong>in</strong> sehr viele Sprachen<br />
• http://cm.bell-labs.com/<br />
cm/cs/cbook/<strong>in</strong>dex.html<br />
Programm<strong>in</strong>g Language Index<br />
• Juli 2012 wieder die meist<br />
verwendete Sprache<br />
• http://www.tiobe.com/<br />
<strong>in</strong>dex.php/content/<br />
paper<strong>in</strong>fo/<br />
tpci/<strong>in</strong>dex.html<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 10 / 326<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Eigenschaften von C<br />
Imperativ, hardwarenah und plattformunabhängig<br />
C is decl<strong>in</strong><strong>in</strong>g somewhat <strong>in</strong> usage compared to C++, and maybe<br />
Java, but perhaps even more compared to higher-level script<strong>in</strong>g<br />
languages. It’s still fairly strong for the basic system-type th<strong>in</strong>gs.<br />
Dennis Ritchie<br />
Erstes Beispiel<br />
“Hello World” <strong>in</strong> C<br />
Imperative/Prozedurale Sprache<br />
• Typen, Variablen, Kontrollstrukturen, Funktionen<br />
• Zeiger und Bitoperationen <strong>in</strong> Sprache <strong>in</strong>tegriert, masch<strong>in</strong>ennah<br />
• Kle<strong>in</strong>er Sprachkern, aber viele Operatoren<br />
• Ke<strong>in</strong>e Objektorientierung<br />
(C++ als C-Erweiterung mit OO-Konzepten)<br />
Getrennte Übersetzung<br />
• Übersetzung von Quelldateien <strong>in</strong> Objektdateien<br />
• L<strong>in</strong>ken der Objektdateien zu ausführbarem Programm<br />
• Ke<strong>in</strong> 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 />
zum<strong>in</strong>dest wenn man entsprechend programmiert<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 />
• Ke<strong>in</strong> Modulkonzept<br />
• Andere Dateien werden <strong>in</strong>kludiert,<br />
(Inhalt an die Stelle “kopieren”)<br />
• Makroanweisungen mit #...<br />
3 Whitespaces nicht relevant<br />
4 Funktionsdef<strong>in</strong>itionen<br />
• E<strong>in</strong>e Hauptfunktion je Programm<br />
• Name ist immer ma<strong>in</strong><br />
1 /* the one and only */<br />
2 #<strong>in</strong>clude <br />
3<br />
4 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
5 pr<strong>in</strong>tf("Hello C World\n");<br />
6 return 0;<br />
7 }<br />
5 Funktionsaufrufe<br />
• pr<strong>in</strong>tf, <strong>in</strong> stdio.h deklariert<br />
• Mit e<strong>in</strong>em Parameter<br />
6 Rückgabewert<br />
• Hauptfunktion gibt immer e<strong>in</strong>en<br />
Integer-Wert zurück<br />
7 Ende der Funktion<br />
• E<strong>in</strong>rückregeln wie <strong>in</strong> Java erlaubt,<br />
andere möglich<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 11 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 12 / 326
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Übersetzen und Starten<br />
Übersetzungsprozess<br />
Separate Übersetzung <strong>in</strong> e<strong>in</strong>e ausführbare Datei<br />
Was passiert bei der Übersetzung im Detail<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 />
Präprozessor<br />
• Fügt Quelltexte/Include-Dateien e<strong>in</strong>, Konvention<br />
Endung .h (Header), sucht Dateien <strong>in</strong> bestimmten<br />
Verzeichnissen /usr/<strong>in</strong>clude/...,<br />
• Textuelle Ersetzungen<br />
C-Compiler<br />
• Übersetzt C-Quellcode <strong>in</strong> hardwarespezifische<br />
Assemblersprache<br />
• Optimierungen<br />
Assembler<br />
• Übersetzt Assembler <strong>in</strong> Masch<strong>in</strong>ensprache<br />
L<strong>in</strong>ker<br />
• B<strong>in</strong>det externen Objektcode e<strong>in</strong> (z.B. pr<strong>in</strong>tf), sucht<br />
Bibliotheken <strong>in</strong> bestimmten Verzeichnissen<br />
/usr/lib/...,<br />
hello.c<br />
gcc hello.c -o hello<br />
Präprozessor<br />
C-Compiler<br />
Assembler<br />
L<strong>in</strong>ker<br />
hello<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 13 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 14 / 326<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Makefiles<br />
Automatisierung des Übersetzungsprozesses ...<br />
Variablen<br />
1 Def<strong>in</strong>ition: 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 />
Makefiles<br />
... etwas ausführlicheres Beispiel, Details im Informationsblatt<br />
Ziel all<br />
• Erstes Ziel ist Default-Ziel<br />
• Konvention all<br />
Trennen Compile/L<strong>in</strong>k<br />
• Erst Objekt-Datei mit -c<br />
• Dann B<strong>in</strong>den/L<strong>in</strong>ken<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 -/b<strong>in</strong>/rm -f hello rot13 rot13.o<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 15 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 16 / 326
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>führung <strong>in</strong> C<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<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, NullPo<strong>in</strong>ter<br />
Plattformunabhängige auf JVM ausführbare<br />
Dateien<br />
Getrennte Übersetzungse<strong>in</strong>heiten,<br />
klassenbasiert<br />
Namensräume<br />
Str<strong>in</strong>g-Typ e<strong>in</strong>gebaut<br />
C<br />
Prozedural, imperativ<br />
Manuelle Speicherverwaltung<br />
ke<strong>in</strong>e Ausnahmen, Konvention Fehler-<br />
Codes<br />
Ke<strong>in</strong>e Laufzeitfehlermeldungen: Abbruch<br />
durch Betriebssystem oder undef<strong>in</strong>iertes<br />
Verhalten<br />
Plattformabhängige<br />
Dateien<br />
Getrennte<br />
dateibasiert<br />
Ke<strong>in</strong>e Namensräume<br />
ausführbare<br />
Übersetzungse<strong>in</strong>heiten,<br />
Ke<strong>in</strong> e<strong>in</strong>gebauter Str<strong>in</strong>g-Typ, Konvention<br />
char-Felder<br />
Variablen und Grundtypen<br />
Variablen und Grundtypen fast wie <strong>in</strong> Java<br />
Lokale Variablen<br />
• Deklaration (oder Vere<strong>in</strong>barung) am<br />
Anfang der Funktion<br />
• Viele Compiler erlauben die<br />
Deklaration an beliebiger Stelle, wie <strong>in</strong><br />
Java. Erst ab C99 erlaubt, vermeiden.<br />
• Erst Typname dann Variablenname<br />
4 Initialisierung möglich<br />
5 Mehrfachvere<strong>in</strong>barung möglich<br />
Ausgabe mit pr<strong>in</strong>tf<br />
• Konvention wie System.out.format<br />
• Dokumentation mit man 3 pr<strong>in</strong>tf<br />
1 #<strong>in</strong>clude <br />
2<br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
4 <strong>in</strong>t i = 3;<br />
5 <strong>in</strong>t j, k;<br />
6 double x = 3;<br />
7 j = 4;<br />
8 pr<strong>in</strong>tf("%d\n", i+j);<br />
9 pr<strong>in</strong>tf("%f\n", x*3.3);<br />
10 return 0;<br />
11 }<br />
7<br />
9.900000<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 17 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 18 / 326<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Nicht <strong>in</strong>itialisierte lokale Variablen<br />
Nicht <strong>in</strong>itialisierte lokale Variablen haben undef<strong>in</strong>ierten Wert<br />
Globale und lokale Variablen<br />
Globale Variablen leben immer und werden <strong>in</strong>itialisiert<br />
Nicht <strong>in</strong>itialisierte lokale Variablen<br />
• Deklarierbar und verwendbar<br />
• “Undef<strong>in</strong>ierter” (beliebiger) Wert<br />
<strong>in</strong> der Variablen k<br />
Compiler/Laufzeit<br />
• Warnung nur bei höchster<br />
Warnstufe<br />
• Ausführung möglich<br />
• Undef<strong>in</strong>iertes Verhalten<br />
Variablen immer mit Wert <strong>in</strong>itialisieren!<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 <strong>in</strong>t j, k;<br />
4 j = 4;<br />
5 pr<strong>in</strong>tf("%d\n%d\n", j, j+k);<br />
6 return 0;<br />
7 }<br />
$ gcc -Wall ./nicht<strong>in</strong>it.c -o nicht<strong>in</strong>it<br />
./nicht<strong>in</strong>it.c: In Funktion "ma<strong>in</strong>":<br />
./nicht<strong>in</strong>it.c:9:9: Warnung: "k" wird <strong>in</strong><br />
Funktion un<strong>in</strong>itialisiert verwendet<br />
$ ./nicht<strong>in</strong>it<br />
4<br />
134513308<br />
Globale/Externe Variablen<br />
• Außerhalb von Funktionen def<strong>in</strong>iert<br />
• Können <strong>in</strong>itialisiert werden<br />
• Wenn nicht explizit <strong>in</strong>itialisiert, werden<br />
sie implizit mit 0 <strong>in</strong>itialisiert<br />
• In allen Funktionen global verfügbar<br />
• In Java nicht vorhanden<br />
Lokale Variablen<br />
• Lebensdauer der Funktion nur<br />
<strong>in</strong>nerhalb e<strong>in</strong>es Blocks<br />
• Innere Variable gleichen Namens<br />
überdeckt äußere<br />
• Wie <strong>in</strong> Java<br />
• Ohne Initialisierung beliebiger Wert<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t i=3;<br />
3 <strong>in</strong>t j,k;<br />
4 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
5 j = 4;<br />
6 pr<strong>in</strong>tf("%d\n%d\n", j, j+k);<br />
7 { <strong>in</strong>t lokal=3;<br />
8 pr<strong>in</strong>tf("%d\n", lokal); }<br />
9 /* lokal nicht mehr vere<strong>in</strong>bart */<br />
10 return 0;<br />
11 }<br />
4<br />
4<br />
3<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 19 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 20 / 326
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Grundtypen – Ganze Zahlen<br />
Grundtypen – Ganze Zahlen, Größen<br />
Typen<br />
Größen-Hierarchie<br />
• char, short, <strong>in</strong>t, long<br />
• Alternativen: short <strong>in</strong>t statt short,<br />
long <strong>in</strong>t statt long<br />
Vorzeichen<br />
• Vorsatz unsigned oder signed,<br />
Vorgabe ist signed<br />
• char kann auch unsigned se<strong>in</strong>,<br />
implementierungsabhängig<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 char c = 17;<br />
4 short s = 300;<br />
5 <strong>in</strong>t i = 66666;<br />
6 long l = 66666L;<br />
7 return 0;<br />
8 }<br />
• char genau 1 Byte groß<br />
• char
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Zeichen<br />
Ke<strong>in</strong> Boolean, sondern ganze Zahlen<br />
Datentyp char<br />
• Ganzzahliger Datentyp<br />
• Steht meist für e<strong>in</strong> Zeichen<br />
• Meist (trotzdem) signed,<br />
implementierungsabhängig<br />
• Genau e<strong>in</strong> Byte groß<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 char c0 = ’A’;<br />
4 char c1 = 65;<br />
5<br />
6 pr<strong>in</strong>tf("%c, %c\n", c0, c1);<br />
7 pr<strong>in</strong>tf("%d, %d\n", c0, c1);<br />
8 pr<strong>in</strong>tf("%d\n", ’A’*’B’);<br />
Ke<strong>in</strong> Boolean <strong>in</strong> C<br />
• ab C99 _Bool<br />
Ganze Zahlen als Boolescher Ausdruck<br />
• Jede ganze Zahl kann als Boolean<br />
<strong>in</strong>terpretiert werden<br />
• Auch Ausdrücke möglich<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 <strong>in</strong>t zahl = 2;<br />
4 if (1)<br />
5 pr<strong>in</strong>tf("ja1\n");<br />
6 if (zahl)<br />
7 pr<strong>in</strong>tf("ja2\n");<br />
8 if (zahl-2)<br />
• Kle<strong>in</strong>ster Datentyp <strong>in</strong> C<br />
Verwendung<br />
• Ganze Zahlen oder Zeichen<br />
• Zeichen s<strong>in</strong>d ganze Zahlen<br />
• Entsprechung ’A’== 65 abhängig<br />
von Umgebung/Compiler<br />
9<br />
10 return 0;<br />
11 }<br />
A, A<br />
65, 65<br />
4290<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 />
9 pr<strong>in</strong>tf("ja3\n");<br />
10 pr<strong>in</strong>tf("%d\n", zahl == 2);<br />
11 return 0;<br />
12 }<br />
ja1<br />
ja2<br />
1<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 25 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 26 / 326<br />
Programmieren <strong>in</strong> C<br />
Variablen und Datentypen<br />
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Aufzählungstypen<br />
Aufzählung mit enum<br />
• Def<strong>in</strong>ition von Konstanten<br />
• Kompatibel zu Typ <strong>in</strong>t<br />
• Durch Komma getrennt<br />
• Optional mit Initialisierung<br />
• Dürfen überall auftauchen wo<br />
Konstanten erwartet werden<br />
(z.B. case <strong>in</strong> switch-Konstrukt)<br />
Initialisierung<br />
• Erste Konstante 0, wenn nicht<br />
<strong>in</strong>itialisiert<br />
• Nächste Konstante immer um 1 höher,<br />
wenn nicht <strong>in</strong>itialisiert<br />
Achtung: Nicht typsicher, ke<strong>in</strong><br />
Wertebereichs-Check<br />
1 #<strong>in</strong>clude <br />
2 enum skat { karo=9, herz, pik, kreuz };<br />
3 enum farbe { rot, gruen=17, blau };<br />
4<br />
5 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
6 enum skat blatt = karo;<br />
7 pr<strong>in</strong>tf("karo=%d, herz=%d, "<br />
8 "pik=%d, kreuz=%d\n",<br />
9 karo, herz, pik, kreuz);<br />
10 pr<strong>in</strong>tf("rot=%d, gruen=%d, blau=%d\n",<br />
11 rot, gruen, blau);<br />
12 blatt = 42; /* ke<strong>in</strong> Check*/<br />
13 return 0;<br />
14 }<br />
karo=9, herz=10, pik=11, kreuz=12<br />
rot=0, gruen=17, blau=18<br />
Mengen mit Bitoperationen – Def<strong>in</strong>ition<br />
Beispiel für Aufzählungstypen<br />
Idee – Interpretiere Zahlen als Bitfeld<br />
• Shift-Operationen um mit 1
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Mengen mit Bitoperationen – Verwendung<br />
Beispiel für Aufzählungstypen<br />
Beispiel<br />
• Sche<strong>in</strong>e von Rudi und Susi ausgeben<br />
• Susi und Rudi haben von den<br />
möglichen fünf Sche<strong>in</strong>e<br />
• Von denen ist nur e<strong>in</strong>er der Gleiche<br />
• Susi fehlen noch zwei Sche<strong>in</strong>e<br />
Ke<strong>in</strong> Wertebereichs-Check<br />
• Susi |= 0xFFFFFF<br />
• Wäre ok<br />
• Ke<strong>in</strong>e Überprüfung ob Wert e<strong>in</strong>er der<br />
Werte des Aufzählungstyps ist<br />
1 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
2 enum Sche<strong>in</strong>e Susi =<br />
3 Prog1 | Prog2 | Theo;<br />
4 <strong>in</strong>t Rudi = Prog1 | Prog3 | ADS;<br />
5<br />
6 pr<strong>in</strong>tsche<strong>in</strong>(Susi);<br />
7 pr<strong>in</strong>tsche<strong>in</strong>(Rudi);<br />
8 pr<strong>in</strong>tsche<strong>in</strong>(Susi|Rudi);<br />
9 pr<strong>in</strong>tsche<strong>in</strong>(Susi&Rudi);<br />
10 pr<strong>in</strong>tsche<strong>in</strong>(~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 />
Variablen Def<strong>in</strong>ition und Deklaration<br />
Variablen Def<strong>in</strong>ition<br />
• Legt Typ fest<br />
• Reserviert Speicherplatz<br />
• Darf nur e<strong>in</strong>mal 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 se<strong>in</strong><br />
Def<strong>in</strong>ition = Deklaration + Speicherplatz<br />
1 extern <strong>in</strong>t exta; /* Deklaration */<br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 return exta;<br />
4 }<br />
5 /* Fehler, exta nicht def<strong>in</strong>iert */<br />
1 extern <strong>in</strong>t exta; /* Deklaration */<br />
2 extern <strong>in</strong>t exta; /* Deklaration */<br />
3<br />
4 <strong>in</strong>t exta = 3; /* Def<strong>in</strong>ition */<br />
5<br />
6 /* <strong>in</strong>t exta = 3; Fehler Redef<strong>in</strong>ition */<br />
7<br />
8 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
9 extern <strong>in</strong>t exta; /* Deklaration */<br />
10 extern <strong>in</strong>t exta; /* Deklaration */<br />
11 /* <strong>in</strong>t exta; lokal nicht erlaubt */<br />
12 }<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 29 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 30 / 326<br />
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Typ-Attribute – konstant<br />
Konstantenvere<strong>in</strong>barung<br />
• Schlüsselwert const<br />
• Wert darf nicht verändert werden<br />
• Def<strong>in</strong>ition ohne Wert möglich (leider),<br />
Vorgabewert ist 0<br />
• extern möglich, muss dann später als<br />
const def<strong>in</strong>iert werden<br />
Verwendung von const im Parametertyp<br />
• Wert darf dann <strong>in</strong> Funktion nicht<br />
verändert werden<br />
• Da Werte kopiert werden, s<strong>in</strong>d<br />
Änderungen an z.B. e<strong>in</strong>em <strong>in</strong>t<br />
sowieso nur lokal<br />
#def<strong>in</strong>e nicht verwenden<br />
• Nicht typsicher, nicht Teil von C<br />
1 #def<strong>in</strong>e PI 3.14 /* boese */<br />
2<br />
3 const double pi = 3.14;<br />
4<br />
5 const <strong>in</strong>t len=7+3;<br />
6<br />
7 extern const <strong>in</strong>t c;<br />
8 const <strong>in</strong>t c=3;<br />
9<br />
10 <strong>in</strong>t f(void) {<br />
11 /* c = 4; Fehler */<br />
12 return c;<br />
13 }<br />
14<br />
15 <strong>in</strong>t f2(const <strong>in</strong>t i) {<br />
16 /* i = 4; Fehler */<br />
17 return i;<br />
18 }<br />
Typ-Attribute – const statt #def<strong>in</strong>e<br />
Präprozessor #def<strong>in</strong>e<br />
• Textersetzung, Text nach ersten<br />
Whitespaces durch Text nach zweiten<br />
Whitespaces<br />
• Ke<strong>in</strong>e Ersetzung <strong>in</strong> Zeichenketten und<br />
<strong>in</strong>nerhalb von Bezeichnern<br />
• Alter Stil, als es const noch nicht gab<br />
• Nicht typsicher, tückisch, vermeiden<br />
Konstanten mit const<br />
• Def<strong>in</strong>ition e<strong>in</strong>er Variablen mit<br />
konstantem Inhalt<br />
• Typsicher, Klar, verwenden<br />
enum für <strong>in</strong>t-Konstanten<br />
• Wenn const nicht geht (z.B.<br />
Feldgrenzen), dann enum verwenden<br />
1 #<strong>in</strong>clude <br />
2<br />
3 #def<strong>in</strong>e 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 #def<strong>in</strong>e LEN 7+3<br />
14 const <strong>in</strong>t len=7+3;<br />
15<br />
16 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
17 pr<strong>in</strong>tf("%3d\n", LEN*3); /* 16 */<br />
18 pr<strong>in</strong>tf("%3d\n", len*3); /* 30 */<br />
19 return 0;<br />
20 }<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 31 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 32 / 326
Programmieren <strong>in</strong> C<br />
Bitoperationen<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>gabe und Ausgabe<br />
Typ-Attribute – volatil<br />
Ausgabe<br />
Variable ändert sich “von außen”<br />
• Variable kann sich ohne E<strong>in</strong>wirkung<br />
des laufenden Programms ändern<br />
• Beispiel: Treiber für e<strong>in</strong>e Hardware,<br />
die Ihren Zustand nicht auf Grund von<br />
Programmabläufen ändert<br />
• Gewünschtes Verhalten:<br />
• Compiler soll ke<strong>in</strong>e Optimierungen<br />
(Elim<strong>in</strong>iation aus Ausdrücken,<br />
Umordnung von Code) vornehmen<br />
• Wert muss jedesmal aus<br />
Speicherbereich gelesen werden<br />
volatil-Vere<strong>in</strong>barung<br />
• Schlüsselwort volatile<br />
1 #<strong>in</strong>clude <br />
2<br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
4 volatile <strong>in</strong>t x=3;<br />
5 <strong>in</strong>t 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 />
pr<strong>in</strong>tf<br />
• Gibt 1. Parameter auf Standardausgabe aus<br />
Aufe<strong>in</strong>anderfolgende Str<strong>in</strong>gs werden zu e<strong>in</strong>em<br />
zusammengefasst – vermeiden<br />
• Ersetzt alle %-Konstrukte <strong>in</strong> 1. Parameter durch<br />
jeweils nächsten Wert <strong>in</strong> den weiteren Parametern<br />
• Wie System.out.format, beliebig viele Parameter<br />
spr<strong>in</strong>tf<br />
• Zusätzlicher 1. Parameter<br />
• In diesen Str<strong>in</strong>g (1. Parameter) wird geschrieben statt<br />
Ausgabe nach stdout<br />
• Achtung: Str<strong>in</strong>g muss lang genug se<strong>in</strong><br />
putchar<br />
• Gibt Paramter (<strong>in</strong>t nicht char) auf stdout aus<br />
• Erlaubt Ausgabe von Steuerzeichen (EOF, . . . )<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 <strong>in</strong>t d=42;<br />
4 char c=’a’;<br />
5 double g=3.14;<br />
6 pr<strong>in</strong>tf(<br />
7 "<strong>in</strong>t: %d\n"<br />
8 "char: %c\n"<br />
9 "double: %e\n",<br />
10 d, c, g);<br />
11 return 0;<br />
12 }<br />
<strong>in</strong>t: 42<br />
char: a<br />
double: 3.140000e+00<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 33 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 34 / 326<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>gabe und Ausgabe<br />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>gabe und Ausgabe<br />
E<strong>in</strong>gabe<br />
scanf<br />
• Liest Zeichen von der Standarde<strong>in</strong>gabe<br />
• Wie <strong>in</strong> 1. Parameter verlangt<br />
• Im Beispiel ist das Leerzeichen <strong>in</strong> der E<strong>in</strong>gabe 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 />
e<strong>in</strong>gelesenen Werte<br />
• Bei Fehlern geht es undef<strong>in</strong>iert weiter<br />
sscanf<br />
• Neuer erster Parameter, der E<strong>in</strong>gabestr<strong>in</strong>g<br />
• E<strong>in</strong>gabestr<strong>in</strong>g statt Lesen von std<strong>in</strong><br />
1 #<strong>in</strong>clude <br />
2<br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
4 <strong>in</strong>t d;<br />
5 char c;<br />
6 double g;<br />
7 scanf("%d %c %lg",<br />
8 &d, &c, &g);<br />
9 pr<strong>in</strong>tf("<strong>in</strong>t: %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 />
Programmieren <strong>in</strong> C<br />
E<strong>in</strong>gabe und Ausgabe<br />
Programmieren <strong>in</strong> C<br />
Kontrollstrukturen<br />
%-Konstrukte<br />
Kontrollstrukturen wie <strong>in</strong> Java<br />
%-Konstrukte für ganze Zahlen<br />
• char: %c, <strong>in</strong>t: %d, %i<br />
• unsigned <strong>in</strong>t: %u dezimal, %o oktal,<br />
%x hexadezimal<br />
• long <strong>in</strong>t: %ld, %li,<br />
short <strong>in</strong>t: %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 E<strong>in</strong>gabe relevant,<br />
Ausgabe wird immer erst m<strong>in</strong>destens<br />
double<br />
Dokumentation<br />
• Mit man pr<strong>in</strong>tf, man scanf<br />
• Gewöhnen Sie sich an man<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>() {<br />
3 unsigned <strong>in</strong>t d = 17;<br />
4 double f = 3.14;<br />
5<br />
6 pr<strong>in</strong>tf("%%u: %u, %%o: %o, %%x: %x\n",<br />
7 d, d, d);<br />
8 pr<strong>in</strong>tf("%%f: %f, %%e: %e, %%g: %g\n",<br />
9 f, f, f);<br />
10 f = 1.000000000000001;<br />
11 pr<strong>in</strong>tf("%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 />
Bed<strong>in</strong>gungen<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, cont<strong>in</strong>ue<br />
• for<br />
anfang 0<br />
anfang 1<br />
anfang 0<br />
• Ke<strong>in</strong>e Variablenbelegung <strong>in</strong> for<br />
• Erlaubt ab C99<br />
1 #<strong>in</strong>clude <br />
2 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
3 <strong>in</strong>t i;<br />
4 for (i=0; i < 3; i++) {<br />
5 <strong>in</strong>t j=2, k=0;<br />
6 while (j)<br />
7 j--;<br />
8 j = 1
Programmieren <strong>in</strong> C<br />
Felder<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Felder<br />
Feldgröße<br />
Feld<br />
<strong>in</strong>t a[10];<br />
Größe des Felds<br />
• Speicherbereich mit mehreren gleich<br />
großen Elementen e<strong>in</strong>es Typs<br />
• Zusammenhängender<br />
Speicherbereich<br />
Felder anlegen<br />
• Def<strong>in</strong>ition mit<br />
[]<br />
• Die Länge des Felds ist e<strong>in</strong> konstanter<br />
Ganzzahlausdruck, Angabe mit<br />
enum-Wert erlaubt<br />
• Ab C99 darf Länge e<strong>in</strong>e Variable se<strong>in</strong><br />
• In GCC erlaubt, nicht verwenden<br />
0 1 2 3 4 5 6 7 8 9<br />
enum { G=10 };<br />
...<br />
<strong>in</strong>t a[G];<br />
• Anzahl der Elemente mal Größe je<br />
Element<br />
• Gesamtgröße außerhalb des Blocks<br />
der Def<strong>in</strong>ition nicht verfügbar<br />
Beispiel<br />
• im Gegensatz zu Java<br />
• 10 Mal e<strong>in</strong> <strong>in</strong>t 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 #<strong>in</strong>clude <br />
2 void f(<strong>in</strong>t a[10]) {<br />
3 pr<strong>in</strong>tf("<strong>in</strong> f : %ld\n", sizeof a);<br />
4 }<br />
5 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
6 <strong>in</strong>t a[10];<br />
7 pr<strong>in</strong>tf("<strong>in</strong> ma<strong>in</strong>: %ld\n", sizeof a);<br />
8 f(a);<br />
9 return 0;<br />
10 }<br />
<strong>in</strong> ma<strong>in</strong>: 40<br />
<strong>in</strong> f : 4<br />
• Index von 0 bis -1<br />
Beispiel: 10 <strong>in</strong>t Werte<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 41 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 42 / 326<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Auf Feldelemente zugreifen<br />
Zugriff außerhalb der Feldgrenzen<br />
Zugriff mit []<br />
• Erlaubt von Index 0 bis Länge-1<br />
• Verwendung auf l<strong>in</strong>ker und rechter<br />
Seite der Zuweisung (=)<br />
• Wie <strong>in</strong> Java<br />
Beispiel<br />
• Initialisierung des Felds mit<br />
Quadratzahlen<br />
• Berechnung der Summe der ersten<br />
G-1 Quadratzahlen <strong>in</strong> Funktion<br />
sum=285<br />
1 #<strong>in</strong>clude <br />
2 enum { G=10 };<br />
3 <strong>in</strong>t dosum(<strong>in</strong>t a[], <strong>in</strong>t length) {<br />
4 <strong>in</strong>t 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 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
11 <strong>in</strong>t a[G], i;<br />
12 for(i=0; i < G; i++) {<br />
13 a[i] = i*i;<br />
14 }<br />
15 pr<strong>in</strong>tf("sum=%d\n", dosum(a, G));<br />
16 return 0;<br />
17 }<br />
Feldgrenzen<br />
• Ke<strong>in</strong>e Überprüfung der Feldgrenzen<br />
• Zugriff zunächst erlaubt<br />
• Verhalten außerhalb der Feldgrenzen<br />
undef<strong>in</strong>iert<br />
• Nicht wie <strong>in</strong> Java,<br />
ke<strong>in</strong>e Laufzeitumgebung wie <strong>in</strong> 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 />
1 <strong>in</strong>t ma<strong>in</strong>(void) { /* felderbumm.c */<br />
2 <strong>in</strong>t a[30];<br />
3 a[30000] = 0;<br />
4 }<br />
Speicherzugriffsfehler<br />
1 <strong>in</strong>t ma<strong>in</strong>(void) { /* feldernbumm.c */<br />
2 <strong>in</strong>t a[30];<br />
3 a[1000] = 0;<br />
4 }<br />
% valgr<strong>in</strong>d ./feldernbumm<br />
== Memcheck, a memory error detector<br />
== Invalid write of size 4<br />
== at 0x4004BC: ma<strong>in</strong> (feldernbumm.c:3)<br />
== Address 0x7ff0012f0 is not stack’d,<br />
malloc’d or (recently) free’d<br />
• Tools wie valgr<strong>in</strong>d helfen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 43 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 44 / 326
Programmieren <strong>in</strong> C<br />
Felder<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Felder kopieren<br />
Mehrdimensionale Felder<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 Feld<strong>in</strong>halte 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 unbed<strong>in</strong>gt was man will<br />
Richtig kopieren<br />
• Feldweise, wie <strong>in</strong> Java<br />
• Genauso bei Vergleich, Ausgabe, etc.<br />
1 #<strong>in</strong>clude <br />
2<br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
4 <strong>in</strong>t a[30], b[30], i;<br />
5 /* a = b; nicht erlaubt */<br />
6 if (a == b)<br />
7 pr<strong>in</strong>tf("NIE\n");<br />
8 for (i=0; i < 30; i++) /* <strong>in</strong>it */<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(<strong>in</strong>t x[30], <strong>in</strong>t y[30]) {<br />
16 x = y; /* erlaubt aber s<strong>in</strong>nlos */<br />
17 }<br />
Def<strong>in</strong>ieren mehrdimensionaler Felder<br />
• Def<strong>in</strong>ition 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 e<strong>in</strong> 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 <strong>in</strong>t a[3][5], i, j;<br />
2 pr<strong>in</strong>tf("%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 pr<strong>in</strong>tf("%2d ", a[i][j]);<br />
10 pr<strong>in</strong>tf("\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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 45 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 46 / 326<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Programmieren <strong>in</strong> C<br />
Felder<br />
Mehrdimensionale Felder als Parameter<br />
Problem – Dimensionen notwendig<br />
• Dimensionen notwendig um Position <strong>in</strong><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(<strong>in</strong>t a[][5], <strong>in</strong>t b[3][5],<br />
2 <strong>in</strong>t c[10][5]) {<br />
3 pr<strong>in</strong>tf("%2d %2d %2d\n",<br />
4 a[1][0], b[1][0], c[1][0]);<br />
5 pr<strong>in</strong>tf("%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(<strong>in</strong>t a[3][], <strong>in</strong>t 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 />
Initialisierung von Feldern<br />
Initialisierungswerte mit {}<br />
• Funktioniert für e<strong>in</strong>dimensionale 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 <strong>in</strong>itialisiert<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 />
• Ke<strong>in</strong>e dynamischen Feldgrößen!<br />
1 <strong>in</strong>t a1[3][5] = { {0,1,2,3,4},<br />
2 {5,6,7,8,9},<br />
3 {10,11,12,13,14} };<br />
4 <strong>in</strong>t 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 <strong>in</strong>t a4[] = {1,2,3};<br />
9 gibaus(a1); /* Ausgabe als Block */<br />
10 gibaus(a2); /* Wie schon angegeben */<br />
11 pr<strong>in</strong>tf("%2d %2d %2d %2d %2d \n",<br />
12 a3[0], a3[1], a3[2], a3[3], a3[4]);<br />
13 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 47 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 48 / 326
Programmieren <strong>in</strong> C<br />
Felder<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Zeichenketten<br />
Getrennte Übersetzung<br />
Ke<strong>in</strong> Zeichenketten-Typ <strong>in</strong> C!<br />
• Ke<strong>in</strong> dedizierter Typ<br />
• Es wird e<strong>in</strong> char-Feld verwendet<br />
• Konvention<br />
• Zeichenkette wird mit Zeichen ’\0’<br />
(der Wert 0) abgeschlossen<br />
Ke<strong>in</strong>e Operatoren auf Zeichenketten<br />
• Ke<strong>in</strong> kopieren, vergleichen,<br />
konkatenieren, . . .<br />
Bibiliotheken<br />
• Operationen s<strong>in</strong>d Teil der<br />
Standardbibliothek<br />
• str<strong>in</strong>g.h, man 3 str<strong>in</strong>g<br />
• Verwendung mit Funktionsaufrufen<br />
Beispiel Zeile 8, ke<strong>in</strong> 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 pr<strong>in</strong>tf("%s %s %s %s\n", s1, s2, s3, s4);<br />
7 strcat(s2,s1);<br />
8 strcat(s3,s1);<br />
9 pr<strong>in</strong>tf("%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 />
Größere Softwareprojekte<br />
• Alles <strong>in</strong> e<strong>in</strong>er Datei nicht mehr s<strong>in</strong>nvoll<br />
• Ke<strong>in</strong>e Modularisierung, ke<strong>in</strong>e Pakete<br />
• Was tun?<br />
Getrennte Übersetzung<br />
• Getrennte Quell-Dateien, .c<br />
• Header-Dateien,<br />
• .h, mit #<strong>in</strong>clude verwenden<br />
• Typ<strong>in</strong>formation, Prototypen, extern<br />
• Separat übersetzen<br />
• -c, nur übersetzen, nicht b<strong>in</strong>den<br />
• Erstellt Objekt-Dateien, .o<br />
• B<strong>in</strong>den (l<strong>in</strong>ken)<br />
• Alle notwendigen Objekt-Dateien,<br />
Abhängigkeiten auflösen<br />
• Ausführbares Programm erzeugen<br />
a.h<br />
b.h<br />
#<strong>in</strong>clude<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 49 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 50 / 326<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Getrennte Übersetzung – Beispiel Fibonacci/1<br />
Separate Fibonacci-Berechnung<br />
• Zwei Methoden, e<strong>in</strong>mal rekursiv<br />
(fibr), e<strong>in</strong>mal iterativ (fibi)<br />
• Gleiche Signatur, von/nach<br />
unsigned <strong>in</strong>t<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 <strong>in</strong>t fibr(unsigned <strong>in</strong>t 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 <strong>in</strong>t fibi(unsigned <strong>in</strong>t n) {<br />
8 unsigned <strong>in</strong>t 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 />
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 pr<strong>in</strong>tf<br />
werden benötigt<br />
• Das Symbol ma<strong>in</strong> wird bereit gestellt<br />
B<strong>in</strong>den (l<strong>in</strong>ken)<br />
• Alle Objekt-Dateien werden<br />
zusammengeklebt<br />
• gcc fibs.o fib.o -o fib<br />
• ma<strong>in</strong> als Start benötigt<br />
• pr<strong>in</strong>tf <strong>in</strong> Standardbibliothek<br />
Ausführen: fib(10) = 55 = 55<br />
fib.c<br />
1 #<strong>in</strong>clude <br />
2 unsigned <strong>in</strong>t fibr(unsigned <strong>in</strong>t);<br />
3 unsigned <strong>in</strong>t fibi(unsigned <strong>in</strong>t);<br />
4<br />
5 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
6 const unsigned <strong>in</strong>t n = 10;<br />
7 pr<strong>in</strong>tf("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 />
pr<strong>in</strong>tf<br />
> ma<strong>in</strong><br />
fibs.o<br />
<<br />
> fibr, fibi<br />
fib<br />
< ma<strong>in</strong><br />
> pr<strong>in</strong>tf<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 51 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 52 / 326
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Header-Dateien<br />
Mehrfach<strong>in</strong>klusion<br />
Problem – Mehrfachangabe Prototypen<br />
an jedem Vorkommen <strong>in</strong> 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 />
• E<strong>in</strong>b<strong>in</strong>den mit #<strong>in</strong>clude<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 e<strong>in</strong>facher möglich<br />
fibs.h<br />
1 unsigned <strong>in</strong>t fibr(unsigned <strong>in</strong>t);<br />
2 unsigned <strong>in</strong>t fibi(unsigned <strong>in</strong>t);<br />
fib.c<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude "fibs.h"<br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
4 const unsigned <strong>in</strong>t n = 10;<br />
5 pr<strong>in</strong>tf("fib(%d) = %d = %d\n",<br />
6 n, fibr(n), fibi(n));<br />
7 return 0;<br />
8 }<br />
fibs.c<br />
1 #<strong>in</strong>clude "fibs.h"<br />
2 unsigned <strong>in</strong>t fibr(unsigned <strong>in</strong>t n) {<br />
3 ...<br />
Mehrfach<strong>in</strong>klusion bei großen Projekten<br />
• Header-Dateien <strong>in</strong>kludieren andere,<br />
die wieder andere Header-Dateien<br />
<strong>in</strong>kludieren<br />
• Dabei kann es passieren, dass e<strong>in</strong>e<br />
Header-Datei mehrfach <strong>in</strong>kludiert wird<br />
Probleme<br />
• Schlimmstenfalls führt dies zu Fehlern<br />
bei der Übersetzung<br />
• Problematische<br />
Mehrfachvere<strong>in</strong>barung zum Beispiel<br />
bei enum<br />
• Endlos-Inklusion falls ursprüngliche<br />
Datei wieder <strong>in</strong>kludiert wird<br />
• Auf alle Fälle unnötig lange<br />
Übersetzungszeit<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 53 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 54 / 326<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Präprozessor<br />
Präprozessor<br />
• Inkludieren mit #<strong>in</strong>clude<br />
• Textersetzungen mit #def<strong>in</strong>e<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 />
E<strong>in</strong>satzgebiet<br />
• Für Konstanten vermeiden<br />
• Für Include-Guards verwenden<br />
1 #<strong>in</strong>clude <br />
2 #def<strong>in</strong>e TOLLE "SUPER"<br />
3 #def<strong>in</strong>e OK 0<br />
4 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
5 pr<strong>in</strong>tf("Hallo %s TOLLE Welt\n", TOLLE);<br />
6 #ifdef TOLLE<br />
7 pr<strong>in</strong>tf("Es ist was def<strong>in</strong>iert\n");<br />
8 #else<br />
9 pr<strong>in</strong>tf("Nix is");<br />
10 #endif<br />
11 return OK;<br />
12 }<br />
# 1 "prepro.c"<br />
# [ ... > 800 Zeilen ...]<br />
<strong>in</strong>t ma<strong>in</strong>(void) {<br />
pr<strong>in</strong>tf("Hallo %s TOLLE Welt\n", "SUPER");<br />
pr<strong>in</strong>tf("Es ist was def<strong>in</strong>iert\n");<br />
return 0;<br />
}<br />
Include-Guards<br />
Ziel: Vermeide Mehrfach-Inklusion<br />
• Wenn e<strong>in</strong>e Header-Datei schon<br />
e<strong>in</strong>mal <strong>in</strong>kludiert wurde,<br />
• Dann <strong>in</strong>kludiere sie nicht mehr<br />
• Es kann nicht s<strong>in</strong>nvoll se<strong>in</strong><br />
• Deklarationen reichen e<strong>in</strong>mal<br />
Lösung: Include-Guard<br />
• Def<strong>in</strong>iere e<strong>in</strong>e Konstante<br />
• Konvention Date<strong>in</strong>ame groß, Sonderzeichen<br />
durch Unterstrich ersetzt<br />
• Prüfe ob Konstante nicht def<strong>in</strong>ert ist<br />
• Berücksichtige Inhalte nur, wenn diese<br />
Konstate nicht def<strong>in</strong>iert ist<br />
• Effekt: Nur bei ersten Mal wird Inhalt<br />
berücksichtigt<br />
fibs.h<br />
1 #ifndef FIBS_H<br />
2 #def<strong>in</strong>e FIBS_H<br />
3<br />
4 unsigned <strong>in</strong>t fibr(unsigned <strong>in</strong>t);<br />
5 unsigned <strong>in</strong>t fibi(unsigned <strong>in</strong>t);<br />
6<br />
7 #endif<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 55 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 56 / 326
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Beispiel Mehrfach<strong>in</strong>klusion mit Include-Guards – Schalter/1<br />
zustaende.h<br />
1 #ifndef ZUSTAENDE_H<br />
2 #def<strong>in</strong>e ZUSTAENDE_H<br />
3 enum zustand {aus, an};<br />
4 extern enum zustand <strong>in</strong>itial;<br />
5 #endif<br />
zustaende.c<br />
1 #<strong>in</strong>clude "zustaende.h"<br />
2 enum zustand <strong>in</strong>itial = aus;<br />
reset.h<br />
1 #<strong>in</strong>clude "zustaende.h"<br />
2 enum zustand reset(void);<br />
wechsel.h<br />
1 #<strong>in</strong>clude "zustaende.h"<br />
2 enum zustand wechsel(<br />
3 enum zustand aktuell);<br />
reset.c<br />
1 #<strong>in</strong>clude "reset.h"<br />
2 static <strong>in</strong>t zaehler=0;<br />
3 static <strong>in</strong>t f(void);<br />
4 enum zustand reset(void) {<br />
5 zaehler += 1+f();<br />
6 return <strong>in</strong>itial;<br />
7 }<br />
8 static <strong>in</strong>t f(void) { return 0; }<br />
wechsel.c<br />
1 #<strong>in</strong>clude "wechsel.h"<br />
2 static <strong>in</strong>t zaehler=0;<br />
3 static <strong>in</strong>t 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 <strong>in</strong>t f(void) { return 0; }<br />
Beispiel Mehrfach<strong>in</strong>klusion mit Include-Guards – Schalter/2<br />
Aufbau<br />
• Wir modellieren e<strong>in</strong>en Schalter<br />
• zustand.h wird von allen gebraucht<br />
• zustand.h wird von reset.h und<br />
wechsel.h <strong>in</strong>kludiert<br />
• Das Hauptprogramm schalter<br />
resetted und schaltet und <strong>in</strong>kludiert<br />
entsprechend<br />
Problem<br />
• Mehrfach<strong>in</strong>klusion <strong>in</strong> e<strong>in</strong>er<br />
Übersetzungsheit von zustand.h<br />
• Übersetzungsfehler<br />
Mehrfachvere<strong>in</strong>barung enum zustand<br />
Lösung: Inlcude-Guard verh<strong>in</strong>dert<br />
Mehrfach<strong>in</strong>klusion<br />
schalter.c<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude "reset.h"<br />
3 #<strong>in</strong>clude "wechsel.h"<br />
4<br />
5 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
6 enum zustand schalter;<br />
7 schalter = reset();<br />
8 pr<strong>in</strong>tf("%u\n", schalter);<br />
9 schalter = wechsel(schalter);<br />
10 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 57 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 58 / 326<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Beispiel Mehrfachdef<strong>in</strong>ition<br />
Problem, Zeile 4<br />
• Def<strong>in</strong>ition <strong>in</strong> e<strong>in</strong>er Header-Datei<br />
• Extrem böse!<br />
• Nie, nie, nie machen<br />
• Da hilft auch ke<strong>in</strong> Include-Guard<br />
Fehlerauftreten<br />
• Sobald Header-Datei <strong>in</strong> zwei<br />
verschiedenen Übersetzungse<strong>in</strong>heiten<br />
verwendet wird<br />
• Zweimal Speicherplatz reserviert für<br />
das gleiche Symbol<br />
Doppelt def<strong>in</strong>iertes Symbol<br />
Vermeiden<br />
• In Header-Datei nur deklarieren<br />
• nie def<strong>in</strong>ieren<br />
zustaende.h<br />
1 #ifndef ZUSTAENDE_H<br />
2 #def<strong>in</strong>e ZUSTAENDE_H<br />
3 enum zustand {aus, an};<br />
4 enum zustand <strong>in</strong>itial=an;<br />
5 #endif<br />
reset.o<br />
< ..<br />
> <strong>in</strong>itial<br />
schalter.o<br />
< ..<br />
> <strong>in</strong>itial<br />
wechsel.o<br />
< ..<br />
> <strong>in</strong>itial<br />
Mehrfach def<strong>in</strong>iertes Symbol <strong>in</strong>itial<br />
Namenskollision und static<br />
Namenskollision<br />
• Situation: In zwei Quelldateien (.c<br />
Übersetzungse<strong>in</strong>heiten) wird zufällig<br />
der gleiche globale Name verwendet<br />
• Effekt: Das B<strong>in</strong>den geht schief (doppelt<br />
def<strong>in</strong>iertes Symbol), die Variable kann<br />
von überall manipuliert werden<br />
Lösung – static<br />
• static def<strong>in</strong>ierte Variable auf globaler<br />
Ebene ist nur lokal für die<br />
Übersetzungse<strong>in</strong>heit def<strong>in</strong>iert<br />
• Variable ist nicht sichtbar <strong>in</strong> anderen<br />
Übersetzungse<strong>in</strong>heiten<br />
• Gleicher Name darf mehrfach<br />
vorkommen<br />
• Dito für static def<strong>in</strong>ierte Funktionen<br />
wechsel.c<br />
1 #<strong>in</strong>clude "wechsel.h"<br />
2 static <strong>in</strong>t zaehler=0;<br />
3 static <strong>in</strong>t f(void);<br />
4 enum zustand wechsel...<br />
5 static <strong>in</strong>t f(void) { return 0; }<br />
reset.c<br />
1 #<strong>in</strong>clude "reset.h"<br />
2 static <strong>in</strong>t zaehler=0;<br />
3 static <strong>in</strong>t f(void);<br />
4 enum zustand reset...<br />
5 static <strong>in</strong>t f(void) { return 0; }<br />
Im Beispiel ist Zaehlvariable zaehler und<br />
Funktion f jeweils nur für<br />
Übersetzungse<strong>in</strong>heit wechsel.c bzw.<br />
reset.c gültig.<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 59 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 60 / 326
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Programmieren <strong>in</strong> C<br />
Getrennte Übersetzung<br />
Komplettes Makefile für schalter /1<br />
1,2 Def<strong>in</strong>ition Compiler und Optionen<br />
3,4 Def<strong>in</strong>ition Programme und Quellen<br />
7 all per Konvention erstes Ziel, soll<br />
“alles” machen<br />
9 Es wird die Datei make.depend<br />
e<strong>in</strong>gelesen und als Teil des Makefiles<br />
<strong>in</strong>terpretiert<br />
11-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 e<strong>in</strong>e leere<br />
Datei erstellen ($ touch<br />
make.depend), damit es los geht.<br />
Ansonsten bei Strukturänderungen<br />
#<strong>in</strong>clude 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 <strong>in</strong>clude 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 />
Komplettes Makefile für schalter /2<br />
Fortsetzung Makefile<br />
1,2 E<strong>in</strong> beliebtes Ziel ist test zur<br />
Test-Automatisierung, e<strong>in</strong> anderes<br />
übliches Ziel wäre run<br />
4 clean ist ke<strong>in</strong>e 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 s<strong>in</strong>d .o, .c und .h<br />
11 Generische Regel: Um e<strong>in</strong>e .o Datei<br />
aus e<strong>in</strong>er .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 -/b<strong>in</strong>/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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 61 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 62 / 326<br />
Programmieren <strong>in</strong> C Zeiger<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 63 / 326<br />
Programmieren <strong>in</strong> C Getrennte Übersetzung<br />
1<br />
Nutzen des Makefiles<br />
$ make -f clean<br />
/b<strong>in</strong>/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 />
Zeiger<br />
Arbeitsspeicher<br />
• . . . ist <strong>in</strong> Speicherzellen e<strong>in</strong>geteilt<br />
• . . . ist Byte-weise adressierbar<br />
• . . . ist Wort-weise strukturiert<br />
• Adressraum meist 2 32 oder 2 64 Bytes<br />
Zeiger<br />
• Speicherzelle, die Adresse e<strong>in</strong>er<br />
anderen Speicherzelle be<strong>in</strong>haltet<br />
• Typisiert, Anfangsadresse e<strong>in</strong>es Werts<br />
Notation Zugriff<br />
• * ptr: Wert auf den der Zeiger ptr<br />
verweist, Inhaltsoperator *<br />
reset.o zustaende.o -o schalter<br />
• &val: Adresse von Wert val,<br />
$ make test<br />
Adressoperator &<br />
./schalter<br />
0<br />
0x0A0 42<br />
0x0A4<br />
*ptr<br />
0x100 0x0A0<br />
&val<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 64 / 326
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Zeiger – Def<strong>in</strong>ition und Verwendung<br />
Zeigergröße<br />
Notation Typ-Def<strong>in</strong>ition<br />
• *: Def<strong>in</strong>iert e<strong>in</strong>en Zeiger<br />
name auf <br />
• Beispiel: <strong>in</strong>t *ptr;<br />
ptr ist Zeiger auf <strong>in</strong>t<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 <strong>in</strong>t val = 42;<br />
2 <strong>in</strong>t *ptr = &val;<br />
3<br />
42<br />
0x0A0<br />
4 pr<strong>in</strong>tf("%d %d %p %p\n",<br />
5 val, *ptr,<br />
6 (void *) &val,<br />
7 (void *) ptr);<br />
*ptr<br />
8 pr<strong>in</strong>tf("%p\n", (void *) &ptr);<br />
&val<br />
Zeigergröße<br />
• Zeigergröße selbst durch Masch<strong>in</strong>e<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 />
• E<strong>in</strong> <strong>in</strong>t und zwei char<br />
• Auf 32-Bit Masch<strong>in</strong>en ist e<strong>in</strong> <strong>in</strong>t 4 Byte<br />
groß und e<strong>in</strong> char 1 Byte<br />
• Zeiger s<strong>in</strong>d auf 32-Bit Masch<strong>in</strong>en 4<br />
Byte groß, unabhängig vom Basis-Typ<br />
42 A B<br />
0x0A0 0x0A4 0x0A5<br />
0x100 0x104 0x108<br />
0x0A0<br />
0x0A4<br />
0x100<br />
0x104<br />
0x108<br />
'A' 'B'<br />
42<br />
0x0A0<br />
0x0A4<br />
0x0A5<br />
1 <strong>in</strong>t a = 42; char b = ’A’, c = ’B’;<br />
2 <strong>in</strong>t *ap = &a; char *bp = &b, *cp = &c;<br />
3<br />
4 pr<strong>in</strong>tf("%d %c %c\n", a, b, c);<br />
5 pr<strong>in</strong>tf("%p %p %p\n",<br />
6 (void *) &a, (void *) &b, (void *) &c);<br />
7 pr<strong>in</strong>tf("%p %p %p\n",<br />
8 (void *) &ap,(void *) &bp, (void *) &cp);<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 65 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 66 / 326<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Zeiger auf Zeichen, Zeichenketten<br />
Zeigerdef<strong>in</strong>ition – Besonderheiten<br />
Zeiger auf Zeichen<br />
• Zeichen (Byte) ist kle<strong>in</strong>ste<br />
adressierbare E<strong>in</strong>heit (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: E<strong>in</strong> Zeichen ist e<strong>in</strong><br />
Ganzzahltyp<br />
Beispielausgabe<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 pr<strong>in</strong>tf("%c %d %p\n",<br />
5 ch, ch, (void *) chptr);<br />
6 chptr = str;<br />
7 pr<strong>in</strong>tf("%c %c %p %p\n",<br />
Syntax: *<br />
• Erst Typname <br />
• Dann Stern *<br />
• Schließlich Variablenname <br />
Beispiel: <strong>in</strong>t *var<br />
Achtung<br />
• Der * bezieht sich auf den<br />
Variablennamen<br />
• Potentielles Problem bei mehreren<br />
Variablen <strong>in</strong> e<strong>in</strong>er Def<strong>in</strong>ition<br />
• Der Typ e<strong>in</strong>es Zeigers ist *<br />
Notationskonvention<br />
1 <strong>in</strong>t* ptr, qtr;<br />
1 /* entspricht */<br />
2 <strong>in</strong>t *ptr;<br />
3 <strong>in</strong>t qtr;<br />
1 <strong>in</strong>t *ptr, *qtr;<br />
1 /* entspricht */<br />
2 <strong>in</strong>t *ptr;<br />
3 <strong>in</strong>t *qtr;<br />
<strong>in</strong>t* ptr;<br />
A 65 0x0A3<br />
B B 0x0A4 0x0A4<br />
8 str[0], *chptr,<br />
9 (void *) chptr, (void *) &str[0]);<br />
• * immer nahe am Variablennamen<br />
• Nie nahe am Typnamen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 67 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 68 / 326
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Vorrangregeln von Operatoren<br />
Zeiger – Beispiele/1<br />
Von hoch nach niedrig:<br />
10 () [] -> .<br />
9 ! ˜ ++ -- + - * & (typ) sizeof<br />
8 * / %<br />
+ -<br />
7 ><br />
6 < >=<br />
== !=<br />
5 &<br />
ˆ<br />
|<br />
4 &&<br />
||<br />
3 ?:<br />
Vorrang<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 />
1 unsigned <strong>in</strong>t u=42;<br />
2 unsigned <strong>in</strong>t *pu = &u;<br />
3 unsigned <strong>in</strong>t **ppu = &pu;<br />
4 unsigned <strong>in</strong>t ***pppu = &ppu;<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 />
pu 0x..<br />
ppu 0x..<br />
pppu 0x..<br />
2 = += -= *= %= ˆ= &= =<br />
1 ,<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 69 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 70 / 326<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Zeiger – Beispiele/2<br />
Zeigeroperationen, Zeiger auf void<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 />
10 pr<strong>in</strong>tf("%p %p\n",<br />
11 (void *) pc, (void *) ppc);<br />
12 xf[0][1] = ppc;<br />
13 **(*px)[0][1] = ’b’;<br />
14 pr<strong>in</strong>tf("%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 />
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 <strong>in</strong>t *ip;<br />
5<br />
6 pr<strong>in</strong>tf((s == cp) ? "==\n" : "!=\n");<br />
7 pr<strong>in</strong>tf((s != cp) ? "!=\n" : "==\n");<br />
8<br />
9 ip = vp; /* ke<strong>in</strong>e Warnung */<br />
10 ip = cp; /* Warnung */<br />
11 ip = (<strong>in</strong>t *) cp; /* ke<strong>in</strong>e Warnung */<br />
12<br />
13 pr<strong>in</strong>tf("%i\n",<br />
14 *ip); /* was auch immer... */<br />
==<br />
==<br />
1819042152<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 71 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 72 / 326
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Zeigerarithmetik<br />
Beipiel – Zeichenketten<br />
Zeiger und Zahlen<br />
p p+1<br />
Zeichenkette s mit Platz am Ende<br />
H a l l o u n d s o . \0<br />
• Addition und Subtraktion erlaubt<br />
• Feld kann Zeiger zugewiesen werden<br />
• Ergebnis ist e<strong>in</strong> Zeiger<br />
• Effekt: Zeiger um Vielfaches des<br />
Platzbedarfs des Grundtyps ändern<br />
• typ *ptr; <strong>in</strong>t i;<br />
<strong>in</strong>t N = sizeof(typ);<br />
• ptr=ptr+i, ptr um i*N Byte erhöhen<br />
• ptr=ptr-i, um i*N Byte verm<strong>in</strong>dern<br />
• ptr++, ptr--, ptr+=i . . . erlaubt<br />
Zeiger und Zeiger<br />
• Nur Subtraktion erlaubt<br />
• Ergebnis ist ganze Zahl<br />
Ke<strong>in</strong>e Zeigerarithmentik mit void *<br />
N Byte<br />
1 <strong>in</strong>t ai[10];<br />
2 <strong>in</strong>t *pi = &ai[0];<br />
3 double ad[10];<br />
4 double *pd = &ad[0];<br />
5 pr<strong>in</strong>tf("%p %p %ld\n",<br />
6 (void *) pi, (void *) (pi+1),<br />
7 ((char *) (pi+1)) - ((char *) pi));<br />
8 pr<strong>in</strong>tf("%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 />
Erste while-Schleife, Zeile 7<br />
• * ptr testet ob das Zeichen 0 ist<br />
• Läuft bis Str<strong>in</strong>g-Ende<br />
Zweite while-Schleife, Zeile 9<br />
• Typische C-Idiom<br />
• Zuweisung, Zeigererhöhung und Test<br />
<strong>in</strong> e<strong>in</strong>er Zeile<br />
• Doppelte Klammer vermeidet<br />
Warnung<br />
Gesamt<br />
• while-Schleifen – strcat(str, ttr)<br />
• for-Schleife – strlen(str)<br />
1 char s[100] = "Hallo";<br />
2 char *p = s;<br />
3 char t[] = " und so.";<br />
4 char *q = t;<br />
5 <strong>in</strong>t 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 pr<strong>in</strong>tf("%s (%d)\n", s, i);<br />
Hallo und so. (13)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 73 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 74 / 326<br />
Programmieren <strong>in</strong> C<br />
Zeiger<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Rechnen mit Zeigern<br />
Zeigerarithmetik, gleicher Zeigertyp<br />
• Nur bei gleichen Zeigertypen s<strong>in</strong>nvoll<br />
• Beispiele<br />
cq - cp == 5<br />
cq == cp + 5<br />
cp == cq - 5<br />
Zeigerarithmetik bei verschiedenen<br />
Zeigertypen ist Uns<strong>in</strong>n<br />
• cq - ip ???<br />
• Ke<strong>in</strong>e Vermischung von Typen, was<br />
bedeutet +1?<br />
1 char cp[] = "abcdefghij";<br />
2 char *cq = cp+5;<br />
3 short <strong>in</strong>t sp[] = {0,1,2,3,4};<br />
4 short <strong>in</strong>t *sq = sp+2;<br />
5 <strong>in</strong>t ip[] = {0, 1, 2};<br />
6 <strong>in</strong>t *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 />
Zeiger und Felder<br />
1 <strong>in</strong>t af[] = {2,3,5,7,11,13,17,19,23,29};<br />
Feldnamen als Zeiger<br />
2 <strong>in</strong>t i=6;<br />
• Der Name e<strong>in</strong>es Feldes kann als<br />
3<br />
konstanter Zeiger auf das erste<br />
4 pr<strong>in</strong>tf("%d == %d\n", af[i], *(af+i));<br />
Element des Feldes verwendet werden 5 pr<strong>in</strong>tf("%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 />
<strong>in</strong>terpretiert<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 pr<strong>in</strong>tf ("%s %c %c", ptr+2,<br />
5 ’A’+ptr[5],<br />
6 3[ptr+1]);<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 75 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 76 / 326
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Zeiger und Felder s<strong>in</strong>d nicht dasselbe/1<br />
Zeiger und Felder s<strong>in</strong>d nicht dasselbe/2<br />
E<strong>in</strong>em Feldnamen kann ke<strong>in</strong> Zeiger<br />
zugewiesen werden<br />
• Der Feldname selbst ist ke<strong>in</strong> Zeiger<br />
• Es wird ke<strong>in</strong> Platz angelegt für den<br />
Feldnamen<br />
E<strong>in</strong> Zeiger selbst braucht Speicherplatz<br />
• Der Zeiger be<strong>in</strong>haltet die Adresse an<br />
der das erste Element des Feldes<br />
beg<strong>in</strong>nt<br />
• E<strong>in</strong> 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 />
Feld von Felder<br />
• E<strong>in</strong> Feld von Feldern ist eigentlich e<strong>in</strong><br />
grosses Feld<br />
• Row Major, zeilenweise<br />
• Die Größe ist fix<br />
Feld von Zeiger<br />
• E<strong>in</strong> Feld von Zeigern ist e<strong>in</strong> normales<br />
e<strong>in</strong>dimensionales Feld<br />
• Die Werte s<strong>in</strong>d Zeiger auf Werte, bzw.<br />
Zeiger auf den Anfang von Feldern<br />
1 char *pp[] =<br />
2 {"e<strong>in</strong>", "kle<strong>in</strong>er", "text"};<br />
3 char vv[][10] =<br />
4 {"e<strong>in</strong>", "kle<strong>in</strong>er", "text"};<br />
5 pr<strong>in</strong>tf("%ld %ld\n", sizeof pp, sizeof vv);<br />
12 30<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 77 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 78 / 326<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Zeigersalat<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 pr<strong>in</strong>tf("%s", **++cpp);<br />
6 pr<strong>in</strong>tf("%s", *--*++cpp+3);<br />
7 pr<strong>in</strong>tf("%s", *cpp[-2]+3);<br />
8 pr<strong>in</strong>tf("%s\n", cpp[-1][-1]+1);<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 pr<strong>in</strong>tf("%s", **++cpp);<br />
6 pr<strong>in</strong>tf("%s", *--*++cpp+3);<br />
7 pr<strong>in</strong>tf("%s", *cpp[-2]+3);<br />
8 pr<strong>in</strong>tf("%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 />
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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 79 / 326<br />
POINT<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 80 / 326
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Zeigersalat – Zeile 6<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 pr<strong>in</strong>tf("%s", **++cpp);<br />
6 pr<strong>in</strong>tf("%s", *--*++cpp+3);<br />
7 pr<strong>in</strong>tf("%s", *cpp[-2]+3);<br />
8 pr<strong>in</strong>tf("%s\n", cpp[-1][-1]+1);<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 pr<strong>in</strong>tf("%s", **++cpp);<br />
6 pr<strong>in</strong>tf("%s", *--*++cpp+3);<br />
7 pr<strong>in</strong>tf("%s", *cpp[-2]+3);<br />
8 pr<strong>in</strong>tf("%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 />
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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 81 / 326<br />
POINTERST<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 82 / 326<br />
Programmieren <strong>in</strong> C<br />
Zeiger und Felder<br />
Programmieren <strong>in</strong> 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 pr<strong>in</strong>tf("%s", **++cpp);<br />
6 pr<strong>in</strong>tf("%s", *--*++cpp+3);<br />
7 pr<strong>in</strong>tf("%s", *cpp[-2]+3);<br />
8 pr<strong>in</strong>tf("%s\n", cpp[-1][-1]+1);<br />
Kommandozeilenparameter<br />
Parameter von ma<strong>in</strong><br />
• Anzahl der Argumente (<strong>in</strong>klusive<br />
Name des Programms)<br />
<strong>in</strong>t argc<br />
• Argumente als Feld von char-Zeigern<br />
char *argv[]<br />
Ähnlich wie <strong>in</strong> Java<br />
• Eigentlich umgekehrt<br />
args.c<br />
1 #<strong>in</strong>clude <br />
2<br />
3 <strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
4 <strong>in</strong>t i;<br />
5 for (i=0; i < argc; i++) {<br />
6 pr<strong>in</strong>tf("%2d: %s\n", i, argv[i]);<br />
7 }<br />
8 return 0;<br />
9 }<br />
0x..<br />
cpp<br />
3<br />
2<br />
0x..<br />
0x..<br />
0x..<br />
1<br />
0x..<br />
0<br />
cp<br />
c<br />
0x..<br />
0x..<br />
0x..<br />
0x..<br />
POINTERSTEW<br />
F I R S<br />
P O I N<br />
N E W \0<br />
E N T E<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 83 / 326<br />
T \0<br />
T \0<br />
R<br />
\0<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 />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 84 / 326<br />
o \0<br />
e \0
Programmieren <strong>in</strong> C<br />
Funktionsparameter<br />
Programmieren <strong>in</strong> C<br />
Strukturen<br />
Funktionsparameter<br />
Strukturen – struct<br />
Grundtypen<br />
• In Java Werte<br />
Änderbare Parameter durch<br />
Verpacken <strong>in</strong> 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 <strong>in</strong> Feld ändern möglich<br />
Zuweisung heißt Referenz kopieren<br />
• In C Parameter als Zeiger übergeben<br />
Werte <strong>in</strong> Feld können geändert<br />
werden<br />
Zuweisung an Feld nicht möglich<br />
1 void f1(<strong>in</strong>t *pi) { *pi = 17; }<br />
2 void g1(<strong>in</strong>t a[]) {<br />
3 <strong>in</strong>t c[3] = {1,2,3};<br />
4 a = c; /* erlaubt */ }<br />
5 void g2(<strong>in</strong>t *a) {<br />
6 <strong>in</strong>t c[3] = {1,2,3}; a = c; }<br />
7 void g3(<strong>in</strong>t *a) { a[0] = 17; }<br />
1 <strong>in</strong>t i=2;<br />
2 <strong>in</strong>t a[3] = {2,3,5};<br />
3 <strong>in</strong>t 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 />
Wie Java-Klasse ohne Methoden<br />
• Alle Komponenten public<br />
Def<strong>in</strong>ition mit struct<br />
• Variablendef<strong>in</strong>ition bei<br />
struct-Deklaration möglich<br />
• Spätere Variablendef<strong>in</strong>ition möglich,<br />
immer mit Schlüsselwort struct<br />
• Initialisierung <strong>in</strong> 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 <strong>in</strong> Java<br />
1234 Susi S<strong>in</strong>nlos<br />
4711 Willi Wahns<strong>in</strong>n<br />
1 struct person {<br />
2 char name[40];<br />
3 unsigned <strong>in</strong>t id;<br />
4 } susi;<br />
5<br />
6 struct person rudi;<br />
7 struct person willi = {<br />
8 "Willi Wahns<strong>in</strong>n",<br />
9 4711<br />
10 };<br />
1 strcpy (susi.name, "Susi S<strong>in</strong>nlos");<br />
2 susi.id = 1234;<br />
3 rudi = willi;<br />
4 willi.id = 123456;<br />
5 willi.name[0] = ’X’;<br />
6 pr<strong>in</strong>tf("%6d %s\n", susi.id, susi.name);<br />
7 pr<strong>in</strong>tf("%6d %s\n", rudi.id, rudi.name);<br />
8 pr<strong>in</strong>tf("%ld\n", sizeof (struct person));<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 85 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 86 / 326<br />
Programmieren <strong>in</strong> C<br />
Strukturen<br />
Programmieren <strong>in</strong> C<br />
Strukturen<br />
Strukturen – Speicherlayout<br />
Speicherlayout<br />
• Compiler entscheidet<br />
• Ke<strong>in</strong>e Annahmen treffen<br />
Beispiel<br />
• F<strong>in</strong>det 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 <strong>in</strong>t b;<br />
4 char c[3];<br />
5 char d[4];<br />
6 <strong>in</strong>t e;<br />
7 };<br />
1 struct p1 p;<br />
2 char *base = (char *) &p;<br />
3 pr<strong>in</strong>tf("== p:%p ==\n", base);<br />
4 pr<strong>in</strong>tf("a:%2ld b:%2ld c:%2ld d:%2ld e:%2ld\n",<br />
lp a b c<br />
5 ((char *) &p.a)-base, ((char *) &p.b)-base,<br />
0x.. 2 0x.. 1 0x.. 0 0x..<br />
6 ((char *) &p.c)-base, ((char *) &p.d)-base,<br />
7 ((char *) &p.e)-base);<br />
== p:0x44ac2d20 ==<br />
a: 0 b: 4 c: 8 d:11 e:16<br />
Strukturen und Zeiger<br />
Zugriff mit -><br />
• pp->id ist Kurzform für (*pp).id<br />
• Erlaubt e<strong>in</strong>fachen Zugriff auf<br />
Komponenten e<strong>in</strong>er Struktur<br />
• Beispiel: 987654 Rudi Ratlos<br />
Bequem bei Zeigerketten<br />
• Beispiel: 0<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 pr<strong>in</strong>tf("%6d %s\n", pp->id, pp->name);<br />
1 struct node {<br />
2 <strong>in</strong>t 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 pr<strong>in</strong>tf("%d\n", lp->next->next->data);<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 87 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 88 / 326
Programmieren <strong>in</strong> C<br />
Typdef<strong>in</strong>ition<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Typdef<strong>in</strong>itionen – typedef<br />
Freispeicherverwaltung<br />
Typdef<strong>in</strong>ition<br />
• Syntax: typedef <br />
• Danach Verwendung von <br />
statt möglich<br />
• Ke<strong>in</strong> neuer Typ, nur e<strong>in</strong> weiterer<br />
Name für denselben Typ<br />
Vorteil<br />
• (Meist) Kürzer<br />
• Portabler, da Typdef<strong>in</strong>ition nur an<br />
e<strong>in</strong>er Stelle steht<br />
Beispiel<br />
• Ke<strong>in</strong>e neuen Typen nur neue Namen<br />
• struct knoten wäre auch ok<br />
• knoten und struct knoten ergeben<br />
ke<strong>in</strong> Namensproblem<br />
1 typedef <strong>in</strong>t 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 <strong>in</strong>t data;<br />
7 } knoten;<br />
8 typedef struct _node {<br />
9 struct _node *next;<br />
10 <strong>in</strong>t 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 />
Speicher anfordern<br />
• Es gibt ke<strong>in</strong> 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 ke<strong>in</strong>en 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: Ke<strong>in</strong>e Compiler-Warnung<br />
• Achtung: (Nicht unbed<strong>in</strong>gt gleich)<br />
Fehler zur Laufzeit<br />
1 <strong>in</strong>t 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 89 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 90 / 326<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Dynamische Speicherverwaltung<br />
Funktionen zur dynamischen Speicherverwaltung<br />
• void *malloc(size_t size)<br />
Reserviert e<strong>in</strong>en size Byte großen Speicherblock<br />
• void *calloc(size_t nEle, size_t eleSize)<br />
Reserviert e<strong>in</strong>en 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 def<strong>in</strong>iert <strong>in</strong> stdlib.h<br />
• size_t ist e<strong>in</strong> vorzeichenloser Ganzzahltyp<br />
Fehlerfall<br />
• Falls beim Allokieren ke<strong>in</strong> Speicherblock mehr zur Verfügung steht wird NULL<br />
zurückgegeben<br />
• NULL ist e<strong>in</strong> Makro, Zeiger auf nicht def<strong>in</strong>ierten Wert, verwenden wie null <strong>in</strong> Java<br />
• NULL ist meist (nicht immer) so def<strong>in</strong>iert: #def<strong>in</strong>e NULL ((void *) 0)<br />
Ke<strong>in</strong>e Garbage-Collection<br />
Achtung Speicherlecks (leak)<br />
• Speicher wird nicht automatisch<br />
freigegeben<br />
• Jeder allokierte Block muss<br />
freigegeben werden<br />
$ leak<br />
Ke<strong>in</strong> 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 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3 #<strong>in</strong>clude <br />
4 <strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
5 <strong>in</strong>t len = 10000, *a, run=1, mallocs=0;<br />
6 while(run) {<br />
7 a = malloc(len*sizeof(<strong>in</strong>t));<br />
8 if (a == NULL) {<br />
9 pr<strong>in</strong>tf("Ke<strong>in</strong> 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 pr<strong>in</strong>tf ("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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 91 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 92 / 326
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Speicherlecks erkennen<br />
valgr<strong>in</strong>d Beispiellauf<br />
Speicherlecks Beispiel<br />
• Beispiel ähnlich<br />
• Lecks ohne Option -f<br />
Speicherlecks erkennen mit valgr<strong>in</strong>d<br />
• valgr<strong>in</strong>d, memory checker<br />
• Instrumentieren von vorhandenem<br />
Code<br />
• E<strong>in</strong>fach vor Programmaufruf<br />
valgr<strong>in</strong>d<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3 #<strong>in</strong>clude <br />
4<br />
5 <strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
6 <strong>in</strong>t len = 10000, run=1, mallocs=0, i;<br />
7 <strong>in</strong>t *aptr;<br />
8 while(run && (mallocs < 1000)) {<br />
9 aptr = malloc(len*sizeof(<strong>in</strong>t));<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 />
$ valgr<strong>in</strong>d ./leakval.exe<br />
==12615== Memcheck, a memory error detector<br />
==12615== HEAP SUMMARY:<br />
==12615== <strong>in</strong> use at exit: 40,000,000 bytes <strong>in</strong> 1,000 blocks<br />
==12615== total heap usage: 1,000 allocs, 0 frees, 40,000,000 bytes allocated<br />
==12615== LEAK SUMMARY:<br />
==12615== def<strong>in</strong>itely lost: 40,000,000 bytes <strong>in</strong> 1,000 blocks<br />
==12615== <strong>in</strong>directly lost: 0 bytes <strong>in</strong> 0 blocks<br />
==12615== possibly lost: 0 bytes <strong>in</strong> 0 blocks<br />
==12615== still reachable: 0 bytes <strong>in</strong> 0 blocks<br />
==12615== suppressed: 0 bytes <strong>in</strong> 0 blocks<br />
$ valgr<strong>in</strong>d ./leakval.exe -f<br />
==12618== Memcheck, a memory error detector<br />
==12618== HEAP SUMMARY:<br />
==12618== <strong>in</strong> use at exit: 0 bytes <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 93 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 94 / 326<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Verkettete Liste – Header<br />
E<strong>in</strong>fach 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 />
Hilfsrout<strong>in</strong>en<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 e<strong>in</strong>fügen, 13 slptr <strong>in</strong>sert(slptr list, const char *s);<br />
<strong>in</strong>sert: Str<strong>in</strong>g 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 #def<strong>in</strong>e SLIST_H<br />
3<br />
4 #def<strong>in</strong>e 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 95 / 326<br />
Verkettete Liste – Implementierung/1<br />
1 void show_list(slptr lis) {<br />
2 for (; lis; lis = lis->next)<br />
3 pr<strong>in</strong>tf("%s ", lis->s);<br />
4 pr<strong>in</strong>tf("\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 />
10 }<br />
11<br />
12 slptr <strong>in</strong>sert(slptr lis, const char *s) {<br />
13 slptr neu = malloc(sizeof(slist));<br />
14 if (neu == NULL)<br />
15 return NULL;<br />
16 scopy(neu->s, s);<br />
17 neu->next = lis;<br />
18 return neu;<br />
19 }<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 96 / 326
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Verkettete Liste – Implementierung/2<br />
Verkettete Liste – SelectionSort<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 />
10 slptr copy_list_reverse(slptr lis) {<br />
11 slptr nlis = NULL;<br />
12 while (lis) {<br />
13 nlis = <strong>in</strong>sert(nlis, lis->s);<br />
14 lis = lis->next;<br />
15 }<br />
16 return nlis;<br />
17 }<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 />
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 h<strong>in</strong>ten aufgebaut, dass man das<br />
nächste (kle<strong>in</strong>ere) 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 <strong>in</strong> neue Liste e<strong>in</strong> (Zeile 15-18)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 97 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 98 / 326<br />
Programmieren <strong>in</strong> C<br />
Freispeicherverwaltung<br />
Programmieren <strong>in</strong> C<br />
Varianten/Unions<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) { /* F<strong>in</strong>de Maximales */<br />
9 if (strcmp(lis->next->s, befmax->next->s) > 0) {<br />
10 befmax = lis;<br />
11 }<br />
12 lis = lis->next;<br />
13 }<br />
14 hlis = befmax->next->next; /* Max. an Anfang der neuen Liste */<br />
15 befmax->next->next = start;<br />
16 start = befmax->next;<br />
17 befmax->next = hlis;<br />
18 }<br />
19 return start;<br />
20 }<br />
Varianten/Unions<br />
Ziel – Wenig Speicherplatz<br />
• Nur e<strong>in</strong>e 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 h<strong>in</strong>tere<strong>in</strong>ander<br />
• Nur e<strong>in</strong>e Variante ist gültig<br />
• Nur diese sollte verwendet werden<br />
• Leider s<strong>in</strong>d alle verwendbar mit dann<br />
meist s<strong>in</strong>nlosen Werten<br />
• Größe ist die Größe der größten<br />
Variante<br />
1 union zahl {<br />
2 <strong>in</strong>t i;<br />
3 char c[12];<br />
4 double d;<br />
5 };<br />
1 union zahl z1;<br />
2 z1.i = 42;<br />
3 pr<strong>in</strong>tf("%12d ", z1.i);<br />
4 strcpy(z1.c, "42");<br />
5 pr<strong>in</strong>tf("%12s ", z1.c);<br />
6 pr<strong>in</strong>tf("%12d ", z1.i);<br />
7 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 99 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 100 / 326
Programmieren <strong>in</strong> C<br />
Varianten/Unions<br />
Programmieren <strong>in</strong> C<br />
Varianten/Unions<br />
Beispiel – Varianten von Personen/1<br />
Beispiel – Varianten von Personen/2<br />
Zwei Personentypen<br />
• Studierende, STUD<br />
• Professoren, PROF<br />
Abbildung mit struct und union<br />
• E<strong>in</strong> struct mit Klassifikator was das<br />
für e<strong>in</strong>e 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 <strong>in</strong>t matnr;<br />
8 double notenschnitt;<br />
9 <strong>in</strong>t semester;<br />
10 } studi;<br />
11 struct {<br />
12 <strong>in</strong>t persnr;<br />
13 <strong>in</strong>t seitjahr;<br />
14 } prof;<br />
15 } details;<br />
16 };<br />
Erstellung von zwei Personen<br />
• E<strong>in</strong>e Studierende Susi<br />
• E<strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 101 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 102 / 326<br />
Programmieren <strong>in</strong> C<br />
Varianten/Unions<br />
Programmieren <strong>in</strong> C<br />
Bitfelder<br />
Beispiel – Varianten von Personen/3<br />
Bitfelder<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 pr<strong>in</strong>tf("%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 pr<strong>in</strong>tf("%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 />
1 struct punkt {<br />
Ziel – Wenig Speicherplatz<br />
2 /* XY-Position: 0-1024 */<br />
• Mehrere Zahlen mit kle<strong>in</strong>em<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 (<strong>in</strong>t) oder 10-12, 16 (short)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 103 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 104 / 326
Programmieren <strong>in</strong> C<br />
Bitfelder<br />
Programmieren <strong>in</strong> C<br />
Funktionszeiger<br />
Bitfelder – Verwendung<br />
Funktionszeiger<br />
x y r g b<br />
1 struct punkt weissediagonale[1024];<br />
2 <strong>in</strong>t 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 />
10 pr<strong>in</strong>tf("%ld\n", sizeof weissediagonale);<br />
8192, entspricht 8 Byte, Trennung an Wortgrenze<br />
Ziel – Parametrisiertes Verhalten<br />
• Ke<strong>in</strong>e Objektorientierung<br />
• Funktionalität zuordnen/kapseln<br />
können<br />
Umsetzung – Zeiger auf Funktion<br />
• Parametervere<strong>in</strong>barung wie gewohnt<br />
• Statt Funktionsname den<br />
Namen des Funktionszeigers <strong>in</strong><br />
Klammern mit e<strong>in</strong>em Stern davor<br />
• (*)<br />
Aufruf<br />
• Inhaltsoperator<br />
• Geht auch direkt mit Namen,<br />
was sonst sollte geme<strong>in</strong>t se<strong>in</strong><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 pr<strong>in</strong>tf("%s, wie geht es?\n", (*gruss1)());<br />
6 pr<strong>in</strong>tf("%s, wie geht es?\n", gruss1());<br />
7 gruss2 = boese;<br />
8 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 105 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 106 / 326<br />
Programmieren <strong>in</strong> C<br />
Funktionszeiger<br />
Programmieren <strong>in</strong> C<br />
Makros<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 <strong>in</strong>t zurück<br />
< 0 wenn kle<strong>in</strong>er, > 0 wenn<br />
größer, = 0 wenn gleich<br />
• Parameter s<strong>in</strong>d 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(<strong>in</strong>t a[], <strong>in</strong>t len) {<br />
2 <strong>in</strong>t i;<br />
3 for (i=0; i < 3; i++)<br />
4 pr<strong>in</strong>tf("%d ", a[i]);<br />
5 pr<strong>in</strong>tf("\n");<br />
6 }<br />
7 <strong>in</strong>t kle<strong>in</strong>er(const void *e1, const void *e2) {<br />
8 return *((<strong>in</strong>t *) e1) - *((<strong>in</strong>t *) e2);<br />
9 }<br />
10 <strong>in</strong>t groesser(const void *e1, const void *e2) {<br />
11 return *((<strong>in</strong>t *) e2) - *((<strong>in</strong>t *) e1);<br />
12 }<br />
1 <strong>in</strong>t a[3] = { 2, 5, 3 };<br />
2 show(a,3);<br />
3 qsort(a, 3, sizeof (<strong>in</strong>t), kle<strong>in</strong>er);<br />
4 show(a,3);<br />
5 qsort(a, 3, sizeof (<strong>in</strong>t), groesser);<br />
6 show(a,3);<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 107 / 326<br />
Makros – Präprozessor<br />
• #<strong>in</strong>clude: Dateien e<strong>in</strong>fügen<br />
• #def<strong>in</strong>e: Ersetzen von Text<br />
• #ifdef, #ifndef, #if def<strong>in</strong>ed, #if !def<strong>in</strong>ed, #if, #else, #elif, #endif, . . .<br />
Bed<strong>in</strong>gte Übersetzung<br />
• Beispiel: Include-Guards<br />
• Beispiel: /usr/<strong>in</strong>clude/stdio.h<br />
1 #ifdef __USE_GNU<br />
2<br />
3 #endif<br />
1 #if def<strong>in</strong>ed __GNUC__ || def<strong>in</strong>ed __USE_GNU<br />
2<br />
3 #endif<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 108 / 326
Programmieren <strong>in</strong> C<br />
Makros<br />
Programmieren <strong>in</strong> C<br />
Makros<br />
Makros – Ersetzen von Text<br />
Ersetzen von Text<br />
• #def<strong>in</strong>e <br />
3 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
• wird durch ersetzt<br />
4 <strong>in</strong>t iPI=0;<br />
• Ersetzungen f<strong>in</strong>den weder <strong>in</strong>nerhalb 5 char *s = " PI ist cool";<br />
von Zeichenketten statt noch <strong>in</strong>nerhalb 6 pr<strong>in</strong>tf("%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 />
• S<strong>in</strong>nvoll zum Beispiel für<br />
Parametrisieren von Typen<br />
makros.c<br />
1 #<strong>in</strong>clude <br />
2 #def<strong>in</strong>e PI 3.1415<br />
8 }<br />
1 $ ./makros<br />
2 3.1415<br />
3 $ gcc -E makros.c | tail<br />
4 # 940 "/usr/<strong>in</strong>clude/stdio.h" 3 4<br />
5 # 2 "makrosa.c" 2<br />
6 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
7 <strong>in</strong>t iPI=0;<br />
8 char *s = " PI ist cool";<br />
9 pr<strong>in</strong>tf("%g\n", 3.1415);<br />
10 return 0;<br />
11 }<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 109 / 326<br />
Makros – Parameter<br />
Makros mit Parametern<br />
• Syntax:<br />
#def<strong>in</strong>e (, ..., ) \<br />
<br />
• Ke<strong>in</strong> Leerzeichen zwischen Namen<br />
und Klammer auf(<br />
• Verwenden der Parameternamen im<br />
<br />
Re<strong>in</strong> textuelle Ersetzung<br />
• Ke<strong>in</strong>e Typen, also ke<strong>in</strong>e<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 #<strong>in</strong>clude <br />
2<br />
3 #def<strong>in</strong>e add1(i,j) i+j<br />
4 #def<strong>in</strong>e mul1(i,j) i*j<br />
1 <strong>in</strong>t i=3, j=4;<br />
2 pr<strong>in</strong>tf("%d\n", mul1(i, j)); /* 12 */<br />
3 pr<strong>in</strong>tf("%d\n", add1(i, j)); /* 7 */<br />
4 pr<strong>in</strong>tf("%d\n", mul1(i+1, j)); /* 7 */<br />
5 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 110 / 326<br />
Programmieren <strong>in</strong> C<br />
Makros<br />
Programmieren <strong>in</strong> C<br />
Makros<br />
Makros – Parameter, Klammern<br />
Makros – Parameter, Klammern, Seiteneffekte<br />
Klammerung der Parameter vermeidet<br />
manche Probleme<br />
Leider nicht alle<br />
1 #def<strong>in</strong>e add2(i,j) ((i) + (j))<br />
2 #def<strong>in</strong>e mul2(i,j) ((i) * (j))<br />
1 <strong>in</strong>t i=3, j=4;<br />
2 pr<strong>in</strong>tf("%d\n", mul2(i, j)); /* 12 */<br />
3 pr<strong>in</strong>tf("%d\n", add2(i, j)); /* 7 */<br />
4 pr<strong>in</strong>tf("%d\n", mul2(i+1, j)); /* 16 */<br />
5 pr<strong>in</strong>tf("%d\n", add2(i, j)*2); /* 14 */<br />
6<br />
7 pr<strong>in</strong>tf("%d\n", add2(++i, ++i)*2); /* 20 */<br />
Zeile 7: Ergebnis 20 statt 18 ???<br />
((++i) + (++i))*2<br />
Seiteneffekte, was soll rauskommen?<br />
Makros können Mehrfachverwendung mit<br />
1 #def<strong>in</strong>e quad(i) ((i)*(i))<br />
unerwünschten Seiteneffekten kaschieren<br />
Nicht machen<br />
1 <strong>in</strong>t i=3;<br />
<strong>in</strong>l<strong>in</strong>e-Funktionen im Header verwenden 2 pr<strong>in</strong>tf("%d\n", quad(++i)); /* 25 */<br />
ab C99<br />
3 pr<strong>in</strong>tf("%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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 111 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 112 / 326
Programmieren <strong>in</strong> C<br />
Konstanten<br />
Programmieren <strong>in</strong> C<br />
Konstanten<br />
Konstanten<br />
Konstanten und Zeiger<br />
Konstanten<br />
• Syntax: const ...<br />
• Modifizierer des Typs<br />
• Compiler stellt sicher, dass der Wert<br />
nicht geändert werden kann<br />
Statt #def<strong>in</strong>e besser const verwenden<br />
• Typüberprüfung f<strong>in</strong>det statt<br />
• Achtung: In Headern als extern<br />
deklarieren ohne Wert und Wert <strong>in</strong><br />
e<strong>in</strong>er Übersetzungse<strong>in</strong>heit def<strong>in</strong>ieren<br />
• Alternative: enum für Feldgrößen da<br />
const dort nicht erlaubt<br />
1 #<strong>in</strong>clude "constlib.h"<br />
2<br />
3 #def<strong>in</strong>e ANTWORT 42<br />
4 const <strong>in</strong>t ANSWER=42;<br />
5<br />
6 #def<strong>in</strong>e AGROESSE 100;<br />
7 enum { ASIZE=100 };<br />
8 char s[ASIZE];<br />
constlib.h<br />
1 #ifndef CONSTLIB_H<br />
2 #def<strong>in</strong>e CONSTLIB_H<br />
3 extern const <strong>in</strong>t THEANSWER;<br />
4 #endif<br />
constlib.c<br />
1 #<strong>in</strong>clude "constlib.h"<br />
2 const <strong>in</strong>t THEANSWER=42;<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 Str<strong>in</strong>g";<br />
12 /* c[0] = ’x’; verboten */<br />
13 /* c = s+1; verboten */<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 113 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 114 / 326<br />
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Programmieren <strong>in</strong> 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: E<strong>in</strong>-/Ausgabe<br />
• stdlib.h: Speicherverwaltung, Str<strong>in</strong>gkonvertierung, Zufallszahlen, . . .<br />
• str<strong>in</strong>g.h: Str<strong>in</strong>g-/Speicherbearbeitung<br />
• time.h: Datum und Uhrzeit<br />
• ....<br />
Teil von ANSI-C / ISO-C<br />
• Syntax und Verhalten def<strong>in</strong>iert<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 115 / 326<br />
Standard-Bibliothek – assert<br />
Zusicherungen<br />
• assert()<br />
• Makro <strong>in</strong> assert.h<br />
• Falls Bed<strong>in</strong>gung nicht erfüllt ist, dann<br />
wird Programm mit entsprechender<br />
Meldung abgebrochen.<br />
Übersetzung<br />
• Ke<strong>in</strong> Code für assert, wenn die<br />
Konstante NDEBUG def<strong>in</strong>iert 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 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3 <strong>in</strong>t mydiv(<strong>in</strong>t zaehler, <strong>in</strong>t nenner) {<br />
4 assert (nenner != 0);<br />
5 return zaehler/nenner;<br />
6 }<br />
7 <strong>in</strong>t ma<strong>in</strong>(void) {<br />
8 pr<strong>in</strong>tf("%d\n", mydiv(17,2));<br />
9 pr<strong>in</strong>tf("%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 />
Float<strong>in</strong>g po<strong>in</strong>t exception<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 116 / 326
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Standard-Bibliothek – Standard I/O<br />
Standard I/O – Beispiel, Datei I/O /1<br />
Zeiger auf Ströme<br />
• std<strong>in</strong> (E<strong>in</strong>gabe), stdout (Ausgabe), stderr (Fehler)<br />
High-Level – gepuffert<br />
• FILE * (Zeiger auf Strom)<br />
• pr<strong>in</strong>tf, scanf; fpr<strong>in</strong>tf, fscanf (Dateien);<br />
spr<strong>in</strong>tf, sscanf (Str<strong>in</strong>gs)<br />
• puts, putc, gets, getchar, getc, fputs, fgetc (s Str<strong>in</strong>g,<br />
c Char)<br />
• fopen, fclose (Dateien); fread, fwrite (b<strong>in</strong>är), . . .<br />
• man stdio<br />
Low-Level – ungepuffert<br />
• <strong>in</strong>t (handle)<br />
• Nicht Teil des ISO-Standards, POSIX-Standard (Unix)<br />
std<strong>in</strong> stdout<br />
Programm<br />
stderr<br />
Ziel<br />
• Datei e<strong>in</strong>lesen, optional<br />
Date<strong>in</strong>ame als<br />
Kommandzeilenparameter,<br />
sonst std<strong>in</strong><br />
• Datei out.strip schreiben<br />
• Zeilenweise<br />
• Innerhalb e<strong>in</strong>er Zeile ke<strong>in</strong>e<br />
Wiederholungen von<br />
Whitespaces<br />
Umsetzung<br />
• stdio, ctype<br />
• Kommaoperator vermeiden<br />
1 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3<br />
4 const char *outfname = "out.strip";<br />
5<br />
6 <strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
7 FILE *fp<strong>in</strong> = std<strong>in</strong>;<br />
8 FILE *fpout = fopen(outfname, "w");<br />
9 <strong>in</strong>t last_space = 0;<br />
10<br />
11 if (argc >= 2) {<br />
12 fp<strong>in</strong> = fopen(argv[1], "r");<br />
13 }<br />
14 if (!fp<strong>in</strong> || !fpout) {<br />
15 fpr<strong>in</strong>tf(stderr, "oopps\n");<br />
16 return -1;<br />
17 }<br />
• open, creat, close, unl<strong>in</strong>k, read, write, lseek, . . .<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 117 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 118 / 326<br />
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Standard I/O – Beispiel, Datei I/O /2<br />
Standard-Bibliothek – Speicherblöcke und Str<strong>in</strong>gs<br />
1 while (!feof(fp<strong>in</strong>)) {<br />
2 <strong>in</strong>t c = fgetc(fp<strong>in</strong>);<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(fp<strong>in</strong>); fclose(fpout);<br />
17 return 0;<br />
18 }<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 />
Str<strong>in</strong>gfunktionen, nur Anfangsadresse (n max. Zeichen)<br />
• strcat, strncat: Zeichenkette anhängen<br />
• strchr: Str<strong>in</strong>g nach Zeichen durchsuchen<br />
• strcmp, strncmp: Str<strong>in</strong>g vergleichen<br />
• strcpy, strncpy: Str<strong>in</strong>g kopieren<br />
• strdup: Str<strong>in</strong>g kopieren, neuer Speicher<br />
• strlen: Länge e<strong>in</strong>es Str<strong>in</strong>gs<br />
• strstr: Nach Teilstr<strong>in</strong>g suchen<br />
• . . .<br />
Speicherfunktionen<br />
0x..0x..0x..0x..0x..0x..<br />
Speicherblöcke beliebiger Länge,<br />
beliebige Struktur (void *)<br />
Str<strong>in</strong>gfunktionen<br />
H A L L O \0<br />
Speicherblöcke beliebiger Länge,<br />
0-term<strong>in</strong>iert, aus Zeichen (char *)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 119 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 120 / 326
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Programmieren <strong>in</strong> C<br />
Standard-Bibliothek<br />
Str<strong>in</strong>gs – Beispiel /1<br />
Str<strong>in</strong>gs – Beispiel /2<br />
Ziel<br />
• Zeichenkette der<br />
Kommandozeile zu e<strong>in</strong>em<br />
dynamisch allokierten Str<strong>in</strong>g<br />
zusammenfügen<br />
Umsetzung<br />
• str<strong>in</strong>g-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 #<strong>in</strong>clude <br />
2 #<strong>in</strong>clude <br />
3 #<strong>in</strong>clude <br />
4<br />
5 <strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
6 <strong>in</strong>t i;<br />
7 <strong>in</strong>t len=1;<br />
8 char *s = malloc(sizeof(char));<br />
9 s[0] = 0;<br />
Komplexität<br />
• Aufwendig wegen strlen<br />
• Viele Allokationen trotz Trick mit<br />
Verdopplung<br />
• Kopieren e<strong>in</strong>es immer wieder<br />
wachsenden Teils<br />
Besser<br />
• Zweimal durchlaufen, e<strong>in</strong>mal<br />
Speicher berechnen, dann<br />
allokieren und füllen<br />
• L<strong>in</strong>ear<br />
1 for (i=1; i
Programmieren <strong>in</strong> Python<br />
E<strong>in</strong>führung<br />
Programmieren <strong>in</strong> Python<br />
E<strong>in</strong>führung<br />
Verbreitung<br />
Umgebung<br />
Plattform für Anwendungen<br />
• Hunderte Skripte <strong>in</strong> /usr/b<strong>in</strong><br />
• Blender, Maya: 3D-Graphik<br />
• Mercurial: Versionsmanagement<br />
• Trac: Projekt/Software Management<br />
• Google App Eng<strong>in</strong>e, Django,<br />
Raspberry Pi<br />
Interner E<strong>in</strong>satz<br />
• Google, NASA, Yahoo, ILM<br />
Entwickler<br />
• Sehr weit verbreitet<br />
• Die meist genutzte “general purpose”<br />
Skriptsprache<br />
• Top Ten <strong>in</strong> TIOBE<br />
http://www.tiobe.com/<strong>in</strong>dex.php/content/<br />
paper<strong>in</strong>fo/tpci/<strong>in</strong>dex.html<br />
Interpreter und Tools<br />
• www.python.org/2.7.3<br />
• Integrierte Entwicklungsumgebung<br />
(IDLE), und <strong>in</strong>teraktiver Interpreter<br />
Interaktive “Shell” <strong>in</strong> 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 />
Onl<strong>in</strong>e-Lektüren (neben Buch)<br />
• docs.python.org/2/tutorial/<br />
• wiki.python.org/mo<strong>in</strong>/Beg<strong>in</strong>nersGuide<br />
• pythonchallenge.com, checkio.org<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 125 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 126 / 326<br />
Programmieren <strong>in</strong> Python<br />
E<strong>in</strong>führung<br />
Programmieren <strong>in</strong> Python<br />
E<strong>in</strong>führung<br />
IDLE Übersicht<br />
Encod<strong>in</strong>g bei Python Skripten – Unicode e<strong>in</strong>stellen<br />
Interaktive Shell und Editoren<br />
• Im Editor mit F5 Programm <strong>in</strong><br />
<strong>in</strong>teraktiver Shell ausführen<br />
• Interaktive Shell ist ke<strong>in</strong> Editor<br />
Integrierter Debugger<br />
• Stop, Over, Out<br />
• Mitlaufen Source<br />
• Anzeige Stack, lokale/globale<br />
Variablen<br />
• Seltener benötigt als <strong>in</strong> C<br />
• Interaktives Testen<br />
• Weniger Fehler <strong>in</strong> Python ;-)<br />
Alternativen<br />
• Emacs: solide, <strong>in</strong>teraktiv<br />
• Eclipse pydev: mächtig, nicht <strong>in</strong>teraktiv<br />
Angabe der Zeichenkodierung<br />
• Erste Zeile im Skript<br />
# -*- cod<strong>in</strong>g: -*-<br />
oder zweite Zeile, falls erste<br />
#!/usr/b<strong>in</strong>/python<br />
• Spezieller Kommentar<br />
• Teilt python (und IDLE) das Encod<strong>in</strong>g<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 />
• Standard Westeuropa, lat<strong>in</strong>1<br />
• Böse: Mac-Roman, cp1285<br />
1 #!/usr/b<strong>in</strong>/python<br />
2 # -*- cod<strong>in</strong>g: utf-8 -*-<br />
3<br />
4 pr<strong>in</strong>t "Hello Python World"<br />
1 Shebang: Starte den<br />
Python-Interpreter mit dem folgenden<br />
Zeilen als <strong>in</strong>teraktive E<strong>in</strong>gabe<br />
2 Encod<strong>in</strong>g: Der ganze Quelltext,<br />
<strong>in</strong>klusive Kommentare und den Texten<br />
<strong>in</strong> Str<strong>in</strong>gs, ist <strong>in</strong> dem angegebenen<br />
Encod<strong>in</strong>g<br />
Alle ausführbaren Programme<br />
mit Zeilen 1 und 2 beg<strong>in</strong>nen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 127 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 128 / 326
Programmieren <strong>in</strong> Python<br />
Erste Schritte<br />
Programmieren <strong>in</strong> Python<br />
Erste Schritte<br />
Erste Schritte – Zahlen und Ausdrücke<br />
Erste Schritte – Zuweisungen und Tests<br />
1 >>> pr<strong>in</strong>t "Hallo Python Welt"<br />
2 Hallo Python Welt<br />
3<br />
4 >>> # Kommentare<br />
1 >>> 6+2 # Ausdruecke<br />
2 8<br />
3<br />
4 >>> 6*2<br />
1 >>> x = 1 # Variablenzuweisung<br />
2 >>> x # hat den zugewiesenen Wert<br />
3 1<br />
4<br />
1 >>> True == 1 # Bool neuer Typ<br />
2 True<br />
3 >>> False == 0<br />
4 True<br />
5<br />
5 12<br />
5 >>> x = y = 2 # Mehrfachzuweisung<br />
5<br />
6<br />
7 >>> 2 # Integer-Zahlen<br />
8 2<br />
9<br />
10 >>> 3.14 # Fliesskommazahlen<br />
11 3.14<br />
12<br />
13 >>> "Str<strong>in</strong>g" # Zeichenketten<br />
14 ’Str<strong>in</strong>g’<br />
15<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 />
6 >>> x<br />
7 2<br />
8 >>> y<br />
9 2<br />
10<br />
11 >>> abs(-3) # e<strong>in</strong>gebaute Funktionen<br />
12 3<br />
13<br />
14 >>> 0 < 1 # Tests<br />
15 True<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 "e<strong>in</strong>s"<br />
15 False<br />
16 >>> 0xff # Hex<br />
17 255<br />
16 >>> 3**4 # Exponenten<br />
17 81<br />
16 >>> 1 < 0<br />
17 False<br />
16 >>> not False<br />
17 True<br />
18<br />
18<br />
18<br />
19 >>> 0377 # Oktal<br />
19 >>> 3+1j # Komplexe Zahlen<br />
19 >>> "e<strong>in</strong>s" and "zwei" # letzter Wert<br />
20 255<br />
20 (3+1j)<br />
20 ’zwei’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 129 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 130 / 326<br />
Programmieren <strong>in</strong> Python<br />
Erste Schritte<br />
Programmieren <strong>in</strong> Python<br />
Erste Schritte<br />
Erste Schritte – B<strong>in</strong>äres Rechnen und Division<br />
Große Zahlen und Konvertierung<br />
1 >>> x = 2 # b<strong>in</strong>aer ...000010<br />
2<br />
3 >>> x >> x & 0xff # b<strong>in</strong>aeres Und<br />
7 2<br />
8<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 />
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 />
1 >>> 3L # explizit grosse Zahlen<br />
2 3L<br />
3 >>> float(3) # explizite Konvertierung<br />
4 3.0 # <strong>in</strong> double<br />
5 >>> <strong>in</strong>t(3.0) # und zurueck<br />
6 3<br />
7 >>> long(3.0) # explizite Konvertierung<br />
8 3L<br />
9 >>> x | 1 # b<strong>in</strong>aeres Oder<br />
10 3<br />
11<br />
12 >>> ~x # Komplement<br />
13 -3<br />
14<br />
15 >>> x^3 # b<strong>in</strong>aeres XOR<br />
16 1<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 />
9 107150860718626732094842504906000181<br />
10 056140481170553360744375038837035105<br />
11 112493612249319837881569585812759467<br />
12 291755314682518714528569231404359845<br />
13 775746985748039345677748242309854210<br />
14 746050623711418779541821530464749835<br />
15 819412673987675591655439460770629145<br />
16 711964776865421676604298316526243868<br />
17 37205668069376L<br />
9 >>> <strong>in</strong>t("12") # auch fuer Str<strong>in</strong>gs<br />
10 12<br />
11 >>> <strong>in</strong>t("11", 16) # explizite Basis<br />
12 17<br />
13<br />
14 >>> <strong>in</strong>t("zwoelf") # nur wenn moeglich<br />
15 # ansonsten Ausnahme<br />
16 Traceback (most recent call last):<br />
17 File "", l<strong>in</strong>e 1, <strong>in</strong> <br />
18 3.0 # anderer Typ<br />
18 ValueError: <strong>in</strong>valid literal for <strong>in</strong>t()<br />
19 >>> 10.0/3<br />
19 with base 10: ’zwoelf’<br />
20 3.3333333333333335<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 131 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 132 / 326
Programmieren <strong>in</strong> Python<br />
Datentypen, Zahlen<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Zahlen<br />
Zahlen und Operationen<br />
Zahlentypen<br />
• ganze Zahlen, <strong>in</strong>t und long (beliebig lang)<br />
• Gleitkommazahlen, float mit double Genauigkeit,<br />
komplexe Zahlen<br />
• Intuitive Darstellung und E<strong>in</strong>gabe<br />
Alle üblichen arithmetischen Operationen<br />
• Standardarithmetik: +, -, * , /, ** , %, //<br />
• Logische Arithmetik: ~, ^, |, &, <br />
• Vorrangregeln und Klammern wie gewohnt<br />
Boolesche Werte: False, True<br />
• Entspricht 0 und 1 (Historie)<br />
• Oder leerer Str<strong>in</strong>g, nichtleerer Str<strong>in</strong>g, . . .<br />
Logische Ausdrücke: and, or, not<br />
• Erstes bestimmendes Element wird zurück gegeben<br />
• Die andere Argumente werden nicht ausgewertet<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 />
1 >>> 0 or ""<br />
2 or "Hallo"<br />
3 or "Welt"<br />
4 ’Hallo’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 133 / 326<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 <strong>in</strong> der <strong>in</strong>teraktiven<br />
Kommandozeile<br />
• Zuweisungen haben ke<strong>in</strong>en Wert<br />
• Wert von Ausdrücken wird<br />
ausgegeben<br />
• pr<strong>in</strong>t 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 >>> pr<strong>in</strong>t lis # 2.x<br />
4 [3, 1, 2]<br />
5 >>> pr<strong>in</strong>t(lis) # 2.x, 3.x<br />
6 [3, 1, 2]<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 134 / 326<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Zahlen<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Ausgabe mit pr<strong>in</strong>t<br />
Ausgabe von Objekten mit pr<strong>in</strong>t<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 Formatstr<strong>in</strong>g, wie <strong>in</strong> C,<br />
%-Operator<br />
• Python 3.x, nur noch <strong>in</strong> Klammern<br />
(jetzt schon möglich)<br />
Alternative<br />
• Ausgabe wie <strong>in</strong> Java<br />
1 >>> lis = [1,2,3]<br />
2 >>> pr<strong>in</strong>t lis, "zwei", 4<br />
3 [1, 2, 3] zwei 4<br />
4 >>> pr<strong>in</strong>t lis,"zwei",4; pr<strong>in</strong>t "weiter"<br />
5 [1, 2, 3] zwei 4<br />
6 weiter<br />
7 >>> pr<strong>in</strong>t lis,"zwei",4,; pr<strong>in</strong>t "weiter"<br />
8 [1, 2, 3] zwei 4 weiter<br />
9 >>> pr<strong>in</strong>t "%s %s" % ("Hallo", "Welt")<br />
10 Hallo Welt<br />
11 >>> pr<strong>in</strong>t(lis)<br />
12 [1, 2, 3]<br />
1 >>> import sys<br />
2 >>> sys.stdout.write("Hallo Welt\n")<br />
3 Hallo Welt<br />
Zeichenkette, Str<strong>in</strong>gs – Darstellung<br />
Syntax<br />
• E<strong>in</strong>fache oder doppelte<br />
Anführungszeichen<br />
• Nicht limitierendes Anführungszeichen<br />
nutzbar<br />
• Alternativ Escape-Zeichen verwenden<br />
Backslash \<br />
Mehrzeilige Str<strong>in</strong>gs<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 ’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 />
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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 135 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 136 / 326
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Str<strong>in</strong>gs – Operationen<br />
Alle üblichen Operationen vorhanden<br />
+ Konkatenation<br />
* Wiederholung<br />
[+i] Indizierung<br />
positive Zahl, 0 ist erstes Zeichen<br />
[-i] Indizierung von h<strong>in</strong>ten<br />
negative Zahl, -1 ist letztes Zeichen<br />
• Slic<strong>in</strong>g<br />
[von:bis] Ausschnitt von <strong>in</strong>klusive, 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 />
Slic<strong>in</strong>g<br />
"SLICEOFSPAM"[von:bis]<br />
• von, e<strong>in</strong>schließend<br />
• bis, ausschließend<br />
Vorzeichen<br />
• Positive Zahlen, von l<strong>in</strong>ks, 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 137 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 138 / 326<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Str<strong>in</strong>gs – Formatierung und Built<strong>in</strong>s<br />
Str<strong>in</strong>gs – Built<strong>in</strong>s und raw Str<strong>in</strong>gs<br />
Formatierung<br />
• Formatstr<strong>in</strong>g und Argumente<br />
• Ähnlich zu C, pr<strong>in</strong>tf<br />
• %s Str<strong>in</strong>g<br />
• %d Zahl<br />
• %x Hexadezimal<br />
• %e, %f, %g Gleitkommaformate<br />
• %% Prozentzeichen<br />
Benamtes Argument<br />
• %()<br />
• Durch bestimmter Wert <strong>in</strong><br />
Abbildung als Argument<br />
• Gefolgt von Argumenttyp<br />
1 >>> "e<strong>in</strong> %s Papagei" % "toter"<br />
2 ’e<strong>in</strong> 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 />
E<strong>in</strong>gebaute Funktionen, Built<strong>in</strong>s<br />
• Länge mit len<br />
• Standardoperationen für Vergleich<br />
• Test auf Enthaltense<strong>in</strong> mit <strong>in</strong><br />
raw Str<strong>in</strong>gs<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" <strong>in</strong> "Hallo"<br />
6 True<br />
1 >>> r"raw \n str<strong>in</strong>g"<br />
2 ’raw \\n str<strong>in</strong>g’<br />
3 >>> pr<strong>in</strong>t r"raw \n str<strong>in</strong>g"<br />
4 raw \n str<strong>in</strong>g<br />
5 >>> "normaler \n str<strong>in</strong>g"<br />
6 ’normaler \n str<strong>in</strong>g’<br />
7 >>> pr<strong>in</strong>t "normaler \n str<strong>in</strong>g"<br />
8 normaler<br />
9 str<strong>in</strong>g<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 139 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 140 / 326
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Str<strong>in</strong>gs<br />
Str<strong>in</strong>gs – weitere Features<br />
Eigenschaften von Str<strong>in</strong>gs<br />
str<strong>in</strong>g-Modul<br />
• als Modul “importieren”<br />
• Funktionen oder Str<strong>in</strong>g-Methoden<br />
• Groß- und Kle<strong>in</strong>schreibung<br />
• Suchen, f<strong>in</strong>den, 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 str<strong>in</strong>g<br />
2 >>> "ab".upper(), str<strong>in</strong>g.upper("ab")<br />
3 (’AB’, ’AB’)<br />
4 >>> str<strong>in</strong>g.f<strong>in</strong>d("spammify", "mm")<br />
5 3<br />
6 >>> str<strong>in</strong>g.atoi("42") # <strong>in</strong>t("42") besser<br />
7 42<br />
8 >>> str<strong>in</strong>g.split("spammify"), "mm")<br />
9 [’spa’, ’ify’]<br />
10 >>> "XX".jo<strong>in</strong>(["spa", "ify"])<br />
11 ’spaXXify’<br />
12 >>> "spa" "XX" "ify"<br />
13 ’spaXXify’<br />
14 >>> str<strong>in</strong>g.strip(" Mean<strong>in</strong>g of Life ")<br />
15 ’Mean<strong>in</strong>g of Life’<br />
1 #!/usr/b<strong>in</strong>/python<br />
2 import sys<br />
3 pr<strong>in</strong>t sys.argv<br />
Str<strong>in</strong>gs s<strong>in</strong>d unveränderlich<br />
• Operation mit Str<strong>in</strong>gs (+, [], etc.)<br />
erzeugen immer neue Str<strong>in</strong>gs<br />
• Vorhandene Str<strong>in</strong>gs werden niemals<br />
verändert<br />
Str<strong>in</strong>gs s<strong>in</strong>d Sequenzen<br />
• Geordnet, die Position der Elemente<br />
ist wichtig<br />
• Klare Menge von unterstützten<br />
Operationen<br />
• Sequenz von Zeichen<br />
Unicode Str<strong>in</strong>gs<br />
• u vor dem Str<strong>in</strong>g<br />
• Typ unicode, nicht str<br />
1 >>> s = "hallo"<br />
2 >>> s[0] = "H"<br />
3 Traceback (most recent call last):<br />
4 File "", l<strong>in</strong>e 1, <strong>in</strong> <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 />
__ma<strong>in</strong>__:1: UnicodeWarn<strong>in</strong>g: Unicode<br />
equal comparison failed...<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 141 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 142 / 326<br />
Programmieren <strong>in</strong> Python<br />
Datentypen, Typhierarchie<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen<br />
Typhierarchie e<strong>in</strong>gebauter Typen<br />
Kollektionen<br />
object als Wurzel für alle Typen<br />
is<strong>in</strong>stance zum Testen<br />
Ganze<br />
Zahlen<br />
<strong>in</strong>t<br />
long<br />
Zahlen<br />
float<br />
complex<br />
fractions.<br />
Fraction<br />
1 >>> is<strong>in</strong>stance(3, <strong>in</strong>t)<br />
2 True<br />
3 >>> is<strong>in</strong>stance(3, object)<br />
4 True<br />
object<br />
Kollektionen<br />
Sequenzen Mengen Abbildungen<br />
unveränderlich veränderlich set dict<br />
str<br />
list<br />
unicode<br />
tuple<br />
E<strong>in</strong>gebaute Kollektionen<br />
• E<strong>in</strong>gebaute Typen zum Verwalten von mehreren Objekten<br />
• Teil der Sprache, nicht nur der Bibliothek<br />
Vorteile<br />
• Effiziente Implementierung<br />
• E<strong>in</strong>fache Formulierung<br />
• Konzentration aufs Problem<br />
nicht auf technische<br />
Implementierungsdetails<br />
Umfangreich<br />
• Alles was man braucht<br />
• Ungefähr java.util.*<br />
• Str<strong>in</strong>gs, 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 143 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 144 / 326
Programmieren <strong>in</strong> Python<br />
Kollektionen, Tupel<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Tupel<br />
Tupel – Sequenz<br />
Tupel – Built<strong>in</strong>s<br />
Tupel s<strong>in</strong>d e<strong>in</strong>e Sequenz<br />
• Syntax n-Tupel, n≥ 2 wie erwartet<br />
• 1-Tupel hat spezielle Syntax<br />
(1) wäre nur e<strong>in</strong> arithmetischer<br />
Ausdruck mit Klammerung<br />
• Leeres Tupel wie erwartet<br />
Beliebig komb<strong>in</strong>ierbar<br />
• Beliebige Typen, schachtelbar<br />
Indizierung<br />
• mit []<br />
• Slic<strong>in</strong>g (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, "e<strong>in</strong>s", 2.0, (34, 4))<br />
12 (1, ’e<strong>in</strong>s’, 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 />
Built<strong>in</strong>s von Sequenzen<br />
• Länge mit len<br />
• Konkatenation mit +<br />
• Wiederholung mit *<br />
• Test auf Enthaltense<strong>in</strong> mit <strong>in</strong><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) <strong>in</strong> 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 >>> pr<strong>in</strong>t 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 145 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 146 / 326<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Tupel<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Listen<br />
Tupel – Unveränderliche Sequenz<br />
Tupel s<strong>in</strong>d unveränderlich<br />
• Operationen mit Tupel erzeugen<br />
neue Tupel<br />
• Achtung! Tupel kann veränderliche<br />
Werte als Tupelelemente haben<br />
Tupel s<strong>in</strong>d Sequenzen<br />
• Geordnet<br />
• Klare Menge unterstützter<br />
Operationen<br />
• Sequenz von Werten beliebigen Typs<br />
im Gegensatz zu Str<strong>in</strong>gs (nur Zeichen)<br />
1 >>> tup = (1,2,3)<br />
2 >>> tup[1] = "zwei"<br />
3 Traceback (most recent call last):<br />
4 File "", l<strong>in</strong>e 1, <strong>in</strong> <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 />
Listen – Sequenz<br />
Syntax wie Tupel<br />
• Umschlossen mit [ und ]<br />
• Ke<strong>in</strong>e spezielle Syntax mehr für<br />
e<strong>in</strong>elementige Listen<br />
• Leere Liste mit []<br />
Beliebig komb<strong>in</strong>ierbar 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 <strong>in</strong> lis<br />
17 True<br />
18 >>> (lis*2)[1:-2]<br />
19 [[2, ’zwei’], (3, ’drei’), 1]<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 147 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 148 / 326
Programmieren <strong>in</strong> Python<br />
Kollektionen, Listen<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Listen<br />
Listen – Veränderliche Sequenz<br />
Listen – Zuweisungen<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 E<strong>in</strong>fluss<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] = "e<strong>in</strong>s"<br />
3 >>> lis<br />
4 [’e<strong>in</strong>s’, 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 />
Zuweisungskompatibilität<br />
• Sequenzen s<strong>in</strong>d untere<strong>in</strong>ander<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, ke<strong>in</strong> 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 />
13 ([’X’, ’Y’], [’c’, ’d’])<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 149 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 150 / 326<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Listen<br />
Programmieren <strong>in</strong> 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, <strong>in</strong>sert<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.<strong>in</strong>sert(0, -1); lis<br />
15 [-1, 0, 1, 2, 3, 4]<br />
16 >>> lis.<strong>in</strong>sert(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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 151 / 326<br />
Listen – E<strong>in</strong>e weitere Sequenz, veränderlich<br />
Listen s<strong>in</strong>d 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 s<strong>in</strong>d Sequenzen<br />
• Ähnlich zu Feld (ArrayList) <strong>in</strong> Java<br />
• Laufzeitverhalten ähnlich zu Feld<br />
Warum Listen und Tupel?<br />
• Bei gemischten Typen eher Tupel;<br />
bei Liste möglich, nicht <strong>in</strong>tuitiv<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 152 / 326
Programmieren <strong>in</strong> Python<br />
Kollektionen, Wörterbücher<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Wörterbücher<br />
Dictionaries, Wörterbücher<br />
Dictionaries – Built<strong>in</strong>s und Schlüsseleigenschaften<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 Hash<strong>in</strong>g<br />
Vorteile<br />
• Verwendung e<strong>in</strong>fach und <strong>in</strong>tuitiv<br />
11<br />
• Schlüssel nicht beschränkt auf Zahlen >>> dic.keys()<br />
12 [’eggs’, ’spam’]<br />
• Ke<strong>in</strong>e 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 Enthaltense<strong>in</strong> 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’ <strong>in</strong> dic<br />
18 True<br />
19 >>> dic.has_key(’spam’)<br />
20 True<br />
E<strong>in</strong>gebaute Funktionen<br />
• len für Anzahl Schlüssel<br />
• del zum Löschen<br />
• Ke<strong>in</strong>e Slic<strong>in</strong>g-Operationen<br />
Dictionary ist ke<strong>in</strong>e Sequenz<br />
Schlüssel unveränderlich<br />
• Intern mit Hash<strong>in</strong>g realisiert<br />
• Zahlen, Str<strong>in</strong>gs, etc.<br />
• Tupel (auch tiefe Strukturen) s<strong>in</strong>d<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 "", l<strong>in</strong>e 1, <strong>in</strong> <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 "", l<strong>in</strong>e 1, <strong>in</strong> <br />
16 TypeError: unhashable type: ’list’<br />
17 >>> dic[’cheese’]<br />
18 Traceback (most recent call last):<br />
19 File "", l<strong>in</strong>e 1, <strong>in</strong> <br />
20 KeyError: ’cheese’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 153 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 154 / 326<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Wörterbücher<br />
Programmieren <strong>in</strong> Python<br />
Kollektionen, Mengen<br />
Dictionaries – Veränderliche Abbildungen<br />
Mengen – Veränderlich, ke<strong>in</strong>e Reihenfolge<br />
Dictionaries s<strong>in</strong>d veränderlich<br />
• Zuweisung mit neuem Schlüssel fügt neue Elemente h<strong>in</strong>zu<br />
• Zuweisung mit existierendem Schlüssel überschreibt Wert<br />
• del löscht Schlüssel/Wert Zuordnung<br />
Dictionaries s<strong>in</strong>d die e<strong>in</strong>zigen Abbildungen<br />
• Ungeordnet (ke<strong>in</strong>e 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 <strong>in</strong>terner Implementierung mit Hash<strong>in</strong>g<br />
• Sonst würde man Wert nicht wiederf<strong>in</strong>den<br />
• Siehe Algorithmen und Datenstrukturen<br />
Mengen<br />
• Ke<strong>in</strong>e doppelten Elemente<br />
• Ke<strong>in</strong>e Reihenfolge, ke<strong>in</strong>e Sequenz<br />
• Realisiert wie Dictionaries,<br />
nur ist der Wert egal<br />
E<strong>in</strong>gebaute Funktionen und Operationen<br />
• len für Anzahl Elemente<br />
• <strong>in</strong> für Test auf Enthaltense<strong>in</strong><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 <strong>in</strong> s<br />
12 True<br />
13 >>> 4 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 155 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 156 / 326
Programmieren <strong>in</strong> Python<br />
Dateien<br />
Programmieren <strong>in</strong> Python<br />
Typen<br />
Dateien<br />
Typ-Überprüfung und Konversion<br />
Modul os für Systemoperationen<br />
• chdir um Verzeichnis zu wechseln<br />
• getcwd um Verzeichnis anzuzeigen<br />
• Unix und W<strong>in</strong>dows Notation<br />
Dateien<br />
•<br />
8<br />
file ist eigener Datentyp<br />
938848<br />
9 >>> <strong>in</strong>halt[700539:700600]<br />
• Konstruktor mit Date<strong>in</strong>ame 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 >>> e<strong>in</strong>gabe.close()<br />
• read zum Lesen der gesamten! Datei<br />
• readl<strong>in</strong>es für Str<strong>in</strong>g-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 >>> e<strong>in</strong>gabe = file("words", "r")<br />
6 >>> <strong>in</strong>halt = e<strong>in</strong>gabe.read()<br />
7 >>> len(<strong>in</strong>halt)<br />
13 >>> os.chdir(’/tmp’)<br />
14 >>> ausgabe = file(’wordskopie’, ’w’)<br />
15 >>> ausgabe.write(<strong>in</strong>halt)<br />
16 >>> ausgabe.close()<br />
Test welcher Typ<br />
• type gibt Typ zurück<br />
• is<strong>in</strong>stance testet ob von Typ<br />
• Vergleich und Auswahl von Typen<br />
Typkonvertierung<br />
• Typname als Funktionsaufruf<br />
Typen<br />
• <strong>in</strong>t, long, float, complex<br />
• str, list, tuple<br />
• dict, . . .<br />
Konversion von/zu Zeichen<br />
• Zeichen <strong>in</strong> Python ke<strong>in</strong>e 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 >>> is<strong>in</strong>stance(lis, list)<br />
8 True<br />
9 >>> <strong>in</strong>t, long, float, complex<br />
10 (, ,<br />
11 , )<br />
12 >>> str, list, tuple, dict<br />
13 (, ,<br />
14 , )<br />
15 >>> <strong>in</strong>t("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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 157 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 158 / 326<br />
Programmieren <strong>in</strong> Python<br />
Typen<br />
Programmieren <strong>in</strong> Python<br />
Variablen<br />
Die Doku ist De<strong>in</strong> Freund<br />
Dokumentation<br />
• docs.python.org<br />
• Tutorial, sehr guter E<strong>in</strong>stieg<br />
• Bibliothek, die Referenz für<br />
alle e<strong>in</strong>gebauten und<br />
anderen Objekte,<br />
Funktionen, Module<br />
Variablen<br />
Verwendung<br />
• Müssen nicht deklariert werden<br />
• Müssen vor erster Verwendung<br />
<strong>in</strong>itialisiert werden<br />
Typ, dynamisch und streng<br />
• Dynamische Typisierung, Variable an<br />
alles b<strong>in</strong>dbar<br />
• Strenge Typisierung, Gebundenes<br />
Objekt hat Typ<br />
Syntaxspezialitäten<br />
• Zuweisung hat ke<strong>in</strong>en Wert<br />
• Mehrfachzuweisung möglich<br />
• Tupelzuweisung<br />
Gültige Variablenbezeichner wie <strong>in</strong> Java,<br />
ke<strong>in</strong>e Schlüsselwörter<br />
1 >>> x = 3<br />
2 >>> x<br />
3 3<br />
4 >>> y<br />
5 NameError: name ’y’ is not def<strong>in</strong>ed<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 ’<strong>in</strong>t’ 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 159 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 160 / 326
Programmieren <strong>in</strong> Python<br />
Variablen<br />
Programmieren <strong>in</strong> Python<br />
Variablen<br />
Zuweisung und Ausdrücke<br />
Gleichheit und Identität<br />
• Alles ist e<strong>in</strong> Objekt<br />
• Gleichheit ==, Objektidentität is<br />
Zuweisung<br />
• Variablen s<strong>in</strong>d Namen, die an Objekte<br />
gebunden s<strong>in</strong>d<br />
• Rechte Seite e<strong>in</strong>er 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 />
• L<strong>in</strong>ke Seite e<strong>in</strong>er Zuweisungen ist e<strong>in</strong>e13 (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 />
e<strong>in</strong> Ausdruck<br />
• [:] macht e<strong>in</strong>e (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 />
Referenzsemantik<br />
Referenzsemantik<br />
• Variablen s<strong>in</strong>d Namen, die an Objekte<br />
gebunden s<strong>in</strong>d<br />
• Rechte Seite e<strong>in</strong>er Zuweisung gibt<br />
Objekt (vorhandenes oder neues)<br />
zurück<br />
• L<strong>in</strong>ke Seite e<strong>in</strong>er Zuweisungen ist e<strong>in</strong>e<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 161 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 162 / 326<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – Verzweigung<br />
if/else Ausdruck statt ?-Operator<br />
Verzweigung<br />
• Schlüsselwörter: if, elif, else<br />
• : Ausdruck, der als<br />
Wahrheitswert <strong>in</strong>terpretiert wird<br />
• : Beliebige Folge von<br />
Anweisungen<br />
Syntax<br />
• Bed<strong>in</strong>gung endet mit Doppelpunkt,<br />
Ke<strong>in</strong>e Klammern notwendig<br />
• ACHTUNG! E<strong>in</strong>rückung ist signifikant<br />
und Teil der Syntax<br />
• Block durch E<strong>in</strong>rücktiefe bestimmt<br />
• E<strong>in</strong>rückung Tabulator oder gleiche<br />
Anzahl an Leerzeichen<br />
• Ke<strong>in</strong>e (geschweiften) Klammern!<br />
E<strong>in</strong>zeiler möglich, vermeiden<br />
if :<br />
<br />
[elif :<br />
]*<br />
[else:<br />
]<br />
1 if 0 == 0:<br />
2 pr<strong>in</strong>t "ja"<br />
3 if "nichtleerer Str<strong>in</strong>g":<br />
4 pr<strong>in</strong>t "ja"<br />
5 else:<br />
6 pr<strong>in</strong>t "ne<strong>in</strong>"<br />
7 if 0:<br />
8 pr<strong>in</strong>t "e<strong>in</strong>s"<br />
9 pr<strong>in</strong>t "zwei"<br />
10 pr<strong>in</strong>t "drei"<br />
11 if 1: pr<strong>in</strong>t "e<strong>in</strong>s"<br />
Syntax ungewöhnlich<br />
• Erst Ergebniswert im “normalen”<br />
Fall<br />
• Dann Bed<strong>in</strong>gung<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 />
// <strong>in</strong> Java, C<br />
? : <br />
1 >>> x, y = 1, 2<br />
2 >>> e = "kle<strong>in</strong>er" if x>> e<br />
4 ’kle<strong>in</strong>er’<br />
and or <br />
1 >>> x, y = 1, 2<br />
2 >>> e = x>> e<br />
4 ’kle<strong>in</strong>er’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 163 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 164 / 326
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – while-Schleife<br />
Kontrollstrukturen – for-Schleife<br />
while-Schleife<br />
• Schlüsselwörter: while, else, break,<br />
cont<strong>in</strong>ue, 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 E<strong>in</strong>rücken als <strong>in</strong>tegraler<br />
Bestandteil der Schleifensyntax<br />
while :<br />
<br />
[else:<br />
]<br />
1 lis = [1, 2, 3, 4]<br />
2 while lis:<br />
3 pr<strong>in</strong>t lis.pop()<br />
4 else:<br />
5 pr<strong>in</strong>t "Ende"<br />
for-Schleife<br />
• Schlüsselwörter: for, <strong>in</strong>, break,<br />
cont<strong>in</strong>ue, pass<br />
• Iterieren über Elemente <strong>in</strong> Sequenzen<br />
• <strong>in</strong> 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 />
for <strong>in</strong> :<br />
<br />
[else:<br />
]<br />
1 for ele <strong>in</strong> ["Hallo", "Welt"]:<br />
2 pr<strong>in</strong>t ele<br />
3 for idx <strong>in</strong> range(1, 4):<br />
4 pr<strong>in</strong>t idx<br />
5 for ch <strong>in</strong> "Hi":<br />
6 pr<strong>in</strong>t ch<br />
4<br />
3<br />
2<br />
1<br />
Ende<br />
• range(von, bis, step)<br />
• Erzeugt e<strong>in</strong>e Liste von Zahlen von<br />
<strong>in</strong>klusive, bis exklusive<br />
• von optional, default 0<br />
• step optional, default 1<br />
Hallo<br />
Welt<br />
1<br />
2<br />
3<br />
H<br />
i<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 165 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 166 / 326<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Kontrollstrukturen – for-Schleife, Dictionaries<br />
Kontrollstrukturen – for-Schleife, typischer E<strong>in</strong>satz<br />
for-Schleife und Dictionaries<br />
• Fragt Objekte, ob sie auch e<strong>in</strong>e<br />
Sequenz se<strong>in</strong> können<br />
• Das Dictionary sagt, ja, dann b<strong>in</strong> ich<br />
e<strong>in</strong>e Sequenz der Schlüssel<br />
• Dann wird über die Schlüssel iteriert<br />
Auch nett mit items und Tupelzuweisung<br />
1 dic = { 1: ’e<strong>in</strong>s’, 2: ’zwei’ }<br />
2 for key <strong>in</strong> dic: # wie dic.keys()<br />
3 pr<strong>in</strong>t key, dic[key]<br />
1 e<strong>in</strong>s<br />
2 zwei<br />
1 dic = { 1: ’e<strong>in</strong>s’, 2: ’zwei’ }<br />
2 pr<strong>in</strong>t dic.items()<br />
3 for key, value <strong>in</strong> dic.items():<br />
4 pr<strong>in</strong>t key, value<br />
[(1, ’e<strong>in</strong>s’), (2, ’zwei’)]<br />
1 e<strong>in</strong>s<br />
2 zwei<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 />
• Ke<strong>in</strong>e expliziten Indexvariablen<br />
• Eleganter<br />
• Ke<strong>in</strong> Indexfehler möglich!<br />
• Funktioniert für alle Sequenzen<br />
1 for idx <strong>in</strong> range(100): # 0-99 <strong>in</strong> Python<br />
2 pr<strong>in</strong>t idx<br />
1 // 0-99 <strong>in</strong> Java<br />
2 for(<strong>in</strong>t i=0; i < 100; i+=1) {<br />
3 System.out.pr<strong>in</strong>tln(idx);<br />
4 }<br />
1 for ele <strong>in</strong> arr: # Feldzugriff <strong>in</strong> Python<br />
2 pr<strong>in</strong>t ele<br />
1 // Feldzugriff <strong>in</strong> Java<br />
2 for(<strong>in</strong>t i=0; i < arr.length; i+=1) {<br />
3 System.out.pr<strong>in</strong>tln(arr[i]);<br />
4 }<br />
1 for e <strong>in</strong> (0, 1, 2, 3): # alle Sequenzen<br />
2 pr<strong>in</strong>t e<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 167 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 168 / 326
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Programmieren <strong>in</strong> Python<br />
Kontrollstrukturen<br />
Schleifenbeispiel – Datei<strong>in</strong>halte durchlaufen<br />
H<strong>in</strong>weise zu Kontrollstrukturen<br />
Dateien mit while<br />
• Endlosschleife mit break<br />
• E<strong>in</strong>lesen bis Fehlschlag<br />
• Schließen optional, aber guter Stil<br />
Dateien mit for<br />
• Eleganter<br />
• Alles E<strong>in</strong>lesen <strong>in</strong> e<strong>in</strong>e Liste<br />
Noch Eleganter<br />
• Default Datei-Aktion ist lesen<br />
• Default ist zeilenweise e<strong>in</strong>lesen<br />
• Automatisch schließen, da offene<br />
Datei nicht gebunden<br />
1 # C-Style :-(<br />
2 e<strong>in</strong>gabe = file("dat.txt", "r")<br />
3 while True:<br />
4 l<strong>in</strong>e = e<strong>in</strong>gabe.readl<strong>in</strong>e()<br />
5 if not l<strong>in</strong>e:<br />
6 break<br />
7 pr<strong>in</strong>t l<strong>in</strong>e<br />
8 e<strong>in</strong>gabe.close()<br />
1 # Besser :-|<br />
2 e<strong>in</strong>gabe = file("dat.txt", "r")<br />
3 for l<strong>in</strong>e <strong>in</strong> e<strong>in</strong>gabe.readl<strong>in</strong>es():<br />
4 pr<strong>in</strong>t l<strong>in</strong>e<br />
5 e<strong>in</strong>gabe.close()<br />
1 # Python-Style :-)<br />
2 for l<strong>in</strong>e <strong>in</strong> file("dat.txt"):<br />
3 pr<strong>in</strong>t l<strong>in</strong>e<br />
Beim Editieren<br />
• Vergessen Sie die Doppelpunkte nicht<br />
• Beg<strong>in</strong>nen Sie immer <strong>in</strong> der ersten Spalte<br />
• Rücken Sie konsistent e<strong>in</strong> (nur Leerzeichen oder nur Tabulatoren)<br />
• Rücken Sie immer gleich weit e<strong>in</strong> (4 Zeichen)<br />
• Oder am besten alles mit der IDLE<br />
Leerzeilen beenden im <strong>in</strong>teraktiven Modus e<strong>in</strong>en Anweisungsblock<br />
Erwarten Sie nicht immer e<strong>in</strong> Ergebnis<br />
• Beispiel: append<br />
Schreiben Sie nicht Java/C <strong>in</strong> Python!<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 169 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 170 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Funktionen<br />
Funktionen – Beispiel, <strong>in</strong>tersect<br />
Def<strong>in</strong>ition mit def<br />
• Erstellt Funktionsobjekt und b<strong>in</strong>det<br />
Namen daran<br />
• return für Rückgabe, ansonsten<br />
automatisch None<br />
• E<strong>in</strong>s oder mehrere<br />
Argumente/Parameter werden<br />
per Namensb<strong>in</strong>dung übergeben<br />
• Dokumentationsstr<strong>in</strong>g <br />
e<strong>in</strong>gebaut, optionale erste Zeile<br />
Auch <strong>in</strong>teraktiv e<strong>in</strong>gebbar<br />
• Leerzeile zum Beenden<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 />
Ziel<br />
• Schnittmenge von Sequenzen<br />
• Abstraktion als Funktion<br />
Lösung<br />
• Python-Funktion <strong>in</strong>tersect<br />
• Ergebnis <strong>in</strong>itial e<strong>in</strong>e leere Sequenz<br />
• Für alle Elemente <strong>in</strong> erster Sequenz<br />
• Suche dieses Element <strong>in</strong> zweiter<br />
Sequenz<br />
• Wenn vorhanden, dann ist es e<strong>in</strong><br />
geme<strong>in</strong>sames Element; füge es zum<br />
Ergebnis h<strong>in</strong>zu<br />
1 def <strong>in</strong>tersect(seq1, seq2):<br />
2 """Schnittmenge von Sequenzen<br />
3 seq1 und seq2"""<br />
4 res = []<br />
5 for ele <strong>in</strong> seq1:<br />
6 if ele <strong>in</strong> seq2:<br />
7 res.append(ele)<br />
8 return res<br />
1 >>> <strong>in</strong>tersect("spam", "scam")<br />
2 [’s’, ’a’, ’m’]<br />
3 >>> <strong>in</strong>tersect([1,2,3], (4,2,6))<br />
4 [2]<br />
• Gib Ergebnis zurück<br />
Beispiele<br />
• Str<strong>in</strong>gs, Listen, Tupel s<strong>in</strong>d Sequenzen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 171 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 172 / 326
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Gültigkeitsbereiche <strong>in</strong> Funktionen<br />
Gültigkeitsbereiche <strong>in</strong> Funktionen – Durchgriff<br />
Funktionsaufrufe s<strong>in</strong>d Namensraum<br />
• Jeder Funktionsaufruf bietet e<strong>in</strong>en<br />
neuen Gültigkeitsbereich<br />
(Namensraum)<br />
• Die Def<strong>in</strong>ition auch<br />
Beispiel f, g<br />
• Variable g wird nicht verändert<br />
• Weder bei der Def<strong>in</strong>ition<br />
• Noch bei dem Aufruf<br />
• g <strong>in</strong> der Funktion ist e<strong>in</strong>e 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 />
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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 173 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 174 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> 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 se<strong>in</strong><br />
Nur lesen automatisch möglich<br />
• Direkter Zugriff auf globalen<br />
Namensraum möglich wie <strong>in</strong> 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 SyntaxWarn<strong>in</strong>g: 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 SyntaxWarn<strong>in</strong>g: name ’g’ is<br />
10 assigned to before global<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 175 / 326<br />
Regeln für Gültigkeitsbereiche<br />
Lokal<br />
• Jeder Funktionsaufruf bietet e<strong>in</strong>en<br />
neuen lokalen Gültigkeitsbereich<br />
(Namensraum)<br />
• Jeder Aufruf, Rekursion funktioniert<br />
• Zugewiesene Namen s<strong>in</strong>d lokal im<br />
aktuellen Gültigskeitsbereich<br />
• können explizit global werden<br />
• Blöcke (E<strong>in</strong>rückungen) s<strong>in</strong>d ke<strong>in</strong><br />
eigener Gültigkeitsbereich<br />
Global<br />
• Das e<strong>in</strong>schließende Modul ist e<strong>in</strong><br />
globaler Gültigkeitsbereich<br />
• Der <strong>in</strong>teraktive Modus ist e<strong>in</strong> Modul,<br />
hat den Namen ’__ma<strong>in</strong>__’<br />
Reservierte Namen s<strong>in</strong>d Teil der Sprache<br />
Reserviert<br />
Modul<br />
Modul<br />
Funktionsdef<strong>in</strong>ition<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Funktionsdef<strong>in</strong>ition<br />
Funktionsdef<strong>in</strong>ition<br />
Funktionsaufruf<br />
Funktionsaufruf<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 176 / 326
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Namensauflösung, LGB-Regel<br />
Namen <strong>in</strong> drei Bereichen suchen<br />
• Erst Lokal<br />
zum Beispiel Variablen und Parameter<br />
<strong>in</strong> def<br />
• Dann Global<br />
zum Beispiel Funktionsdef<strong>in</strong>ition,<br />
Variablen auf oberster Ebene<br />
• Dann e<strong>in</strong>geBaute<br />
built<strong>in</strong>, reservierte Namen, zum<br />
Beispiel len, file<br />
Namensb<strong>in</strong>dungen<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 />
e<strong>in</strong>geBaut<br />
4 pr<strong>in</strong>t a,b<br />
5 >>> f()<br />
6 3 2<br />
7 >>> a,b<br />
8 (1, 2)<br />
Global<br />
Lokal<br />
9 >>> list = "ke<strong>in</strong> Typ mehr, vermeiden"<br />
Parameterübergabe<br />
Parameterübergabe ist Namensb<strong>in</strong>dung<br />
• Parameternamen werden an<br />
übergebene Objekte gebunden<br />
• Neue lokale Namen<br />
• B<strong>in</strong>dung von Namen an Objekt<br />
bee<strong>in</strong>flusst Objekt nicht<br />
Verwendung<br />
• Call by Reference<br />
• Das Ändern e<strong>in</strong>es änderbaren Objekts<br />
hat Auswirkungen (Seiteneffekte)<br />
• Bei unveränderlichen Objekten kann<br />
es ke<strong>in</strong>e 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 177 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 178 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Parameterübergabe – Vorgabewerte<br />
Vorgabewerte – Anwendungsbeispiel<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 h<strong>in</strong>ter<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 e<strong>in</strong>gesetzt<br />
1 def <strong>in</strong>k(x, a=1):<br />
2 return x+a<br />
1 >>> <strong>in</strong>k(3)<br />
2 4<br />
3 >>> <strong>in</strong>k(3, 1)<br />
4 4<br />
5 >>> <strong>in</strong>k(3, 17)<br />
6 20<br />
Suche von Elementen <strong>in</strong> Sequenz<br />
• Vorgabewerte für start und ende<br />
des Suchbereichs<br />
• S<strong>in</strong>nvolle Vorgabe ist 0 für start<br />
und Länge der Sequenz für ende<br />
Nutzung<br />
• Automatische Belegung von<br />
l<strong>in</strong>ks 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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 179 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 180 / 326
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Vorgabewerte – Besonderheiten<br />
1 def suche(seq,ele,start=0,ende=len(seq)):<br />
Gültigkeit<br />
2 for pos <strong>in</strong> range(start, ende):<br />
• Parametername während der<br />
3 ...<br />
Def<strong>in</strong>ition der Vorgabewerte noch nicht 4 Traceback (most recent call last):<br />
nutzbar<br />
5 File "", l<strong>in</strong>e 1, <strong>in</strong> <br />
• Umgehen durch Markieren mit None<br />
und dynamische Berechnung<br />
Lebenszyklus<br />
• Vorgabewert wird nur e<strong>in</strong>mal<br />
ausgewertet, bei der<br />
Funktionsdef<strong>in</strong>ition<br />
• Überraschungen bei änderbaren<br />
Vorgabewerten<br />
• Änderungen bleiben über Aufrufe<br />
h<strong>in</strong>weg enthalten<br />
• Vermeiden durch Markieren mit None<br />
und dynamische Berechnung<br />
6 NameError: name ’seq’ is not def<strong>in</strong>ed<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 181 / 326<br />
Parameterübergabe mit Schlüsselwort<br />
Ziel<br />
• Viele Vorgabewerte verwenden, aber<br />
e<strong>in</strong>ige 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 l<strong>in</strong>ke Seite<br />
e<strong>in</strong>er 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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 182 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Argumente sammeln mit * und **<br />
Weitere Positionsparameter *<br />
• E<strong>in</strong>e Variable am Ende kann mit e<strong>in</strong>em<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 pr<strong>in</strong>t<br />
Weitere Schlüsselwortparameter **<br />
• E<strong>in</strong>e Variable ganz am Ende kann mit<br />
zwei Sternen ** versehen werden<br />
11 SyntaxError: non-keyword arg after<br />
• Dar<strong>in</strong> werden alle weiteren<br />
12 keyword arg<br />
Schlüsselwortparameter als Dictionary<br />
gesammelt<br />
• Die Schlüssel s<strong>in</strong>d die<br />
Variablennamen als Str<strong>in</strong>gs<br />
1 def params(x, y, *pos, **key):<br />
2 pr<strong>in</strong>t 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 "", l<strong>in</strong>e 1<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 183 / 326<br />
Funktionen <strong>in</strong> Funktionen und die LEGB-Regel<br />
Funktionsdef<strong>in</strong>itionen während<br />
Funktionsausführung<br />
• S<strong>in</strong>d erlaubt und s<strong>in</strong>nvoll<br />
• Umfassen aktuellen Namensraum und<br />
halten ihn fest (Enclos<strong>in</strong>g)<br />
• Von <strong>in</strong>nen nach außen<br />
LEGB-Regel<br />
• LGB-Regel erweitert<br />
• Zwischen Lokal und Global<br />
• Man sucht im umschließenden<br />
Namensraum, <strong>in</strong> dem die Funktion<br />
def<strong>in</strong>iert wurde<br />
• Dies ist entweder der globale<br />
Namensraum oder e<strong>in</strong> anderer<br />
Funktionsaufruf als Namensraum<br />
g 1 2 3<br />
e 6 5 3<br />
l 4 5 3<br />
e<strong>in</strong>geBaut<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 />
E<strong>in</strong>gekapselt<br />
Lokal<br />
6 pr<strong>in</strong>t "e", x, y, z # 6, 5, 3<br />
7 g()<br />
8 pr<strong>in</strong>t "l", x, y, z # 4, 5, 3<br />
9 pr<strong>in</strong>t "g", x, y, z # 1, 2, 3<br />
10 f()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 184 / 326
Programmieren <strong>in</strong> Python<br />
Funktionen<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Programmierung<br />
Design-Pr<strong>in</strong>zipien für Funktionen<br />
Parameter verwenden<br />
• Ke<strong>in</strong>e globalen Variablen verwenden<br />
• Flexible Gestaltung der übergebbaren<br />
Parameter möglich<br />
• Reduziert Abhängigkeiten<br />
Rückgaben verwenden<br />
• Ke<strong>in</strong>e globalen Variablen verwenden<br />
• Modifikation von Parametern meiden<br />
• Mehrere Werte als Tupel zurückgeben<br />
• Modifikation ok <strong>in</strong> Klassen/Methoden<br />
Verschachtelte Funktionen mit Vorsicht<br />
• Def<strong>in</strong>ition e<strong>in</strong>er Funktion <strong>in</strong> e<strong>in</strong>er<br />
Funktion nur wenn notwendig<br />
• Anonyme Funktionen s<strong>in</strong>d 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 185 / 326<br />
Anonyme Funktion, Lambda-Ausdrücke<br />
Funktionen s<strong>in</strong>d auch Objekte<br />
• Funktionsobjekte s<strong>in</strong>d normale<br />
Objekte, “first class citizens”<br />
• Funktionsnamen s<strong>in</strong>d an<br />
Funktionsobjekte gebunden<br />
• Def<strong>in</strong>ition von Funktionsobjekten und<br />
B<strong>in</strong>dung an e<strong>in</strong>en Namen mit def<br />
Funktionsobjekte<br />
• Erzeugen e<strong>in</strong>es 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 <strong>in</strong>k(x):<br />
2 return x+1<br />
3 >>> <strong>in</strong>k(3)<br />
4 4<br />
5 >>> <strong>in</strong>k<br />
6 <br />
7 >>> x+1<br />
8 NameError: name ’x’ is not def<strong>in</strong>ed<br />
1 >>> lambda x: x+1<br />
2 <br />
3 >>> <strong>in</strong>k2 = lambda x: x+1<br />
4 >>> <strong>in</strong>k2<br />
5 <br />
6 >>> <strong>in</strong>k2(3)<br />
7 4<br />
8 >>> (lambda x: x+1)(3)<br />
9 4<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 186 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Programmierung<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Funktionales Programmieren<br />
Funktionale Primitive – map<br />
Funktionales Programmieren,<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: E<strong>in</strong>gebaute 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 187 / 326<br />
Funktion auf allen Elementen<br />
• Für alle Objekte von Sequenzen e<strong>in</strong>e<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 E<strong>in</strong>gabesequenz<br />
• Kürzeste Sequenz bestimmt Länge<br />
des Ergebnisses<br />
Beispiele<br />
• Erhöhe alle Werte um 1<br />
• Addiere die Inhalte e<strong>in</strong>er Liste<br />
paarweise<br />
1 >>> def <strong>in</strong>k(x):<br />
2 return x+1<br />
3 >>> map(<strong>in</strong>k, [1, 2, 3])<br />
4 [2, 3, 4]<br />
5 >>> map(lambda x: x+1, [1, 2, 3])<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 188 / 326
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
E<strong>in</strong>satzbeispiel für map<br />
map illustriert<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 />
• E<strong>in</strong>zeiler mit map<br />
• Liste der Zahlen mit range<br />
• Quadrieren als Lambda-Funktion<br />
• Ke<strong>in</strong>e Schleifen<br />
1 def quadratzahlen(von=1, bis=10):<br />
2 lis = []<br />
3 for i <strong>in</strong> range(von, bis+1):<br />
4 lis.append(i*i)<br />
5 return lis<br />
6<br />
7 pr<strong>in</strong>t 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 pr<strong>in</strong>t quadratzahlen()<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 189 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 190 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Funktionale Primitive – filter<br />
E<strong>in</strong>satzbeispiel für filter<br />
Nur Elemente für die Funktion ok ist<br />
• Für alle Objekte e<strong>in</strong>er Sequenz e<strong>in</strong>e<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 />
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 />
• E<strong>in</strong>zeiler mit filter<br />
• Liste der Zahlen mit range<br />
• Funktion zum Testen ob Primzahl wie<br />
bei for-Schleife<br />
• Ke<strong>in</strong>e Schleifen<br />
1 def is_prim(zahl):<br />
2 for teiler <strong>in</strong> 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 <strong>in</strong> range(2, 100):<br />
9 if is_prim(zahl):<br />
10 primzahlen.append(zahl)<br />
11 return primzahlen<br />
12 pr<strong>in</strong>t 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 191 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 192 / 326
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Funktionale Primitive – reduce<br />
Alle Elemente e<strong>in</strong>er Sequenz mit<br />
e<strong>in</strong>er Funktion komb<strong>in</strong>ieren<br />
• Kumuliere alle Objekte e<strong>in</strong>er<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 <strong>in</strong> 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 />
l<strong>in</strong>ksassoziativen 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 />
Str<strong>in</strong>gkonkatenation<br />
19 ["Hallo", "tolle", "Welt"], "")<br />
20 ’ Hallo tolle Welt’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 193 / 326<br />
reduce illustriert<br />
Initialer<br />
Wert<br />
Kumulierte<br />
Werte<br />
0<br />
0 + 1<br />
2 + 1<br />
3 + 3<br />
6 + 4<br />
10 + 5<br />
15 + 6<br />
1 >>> add = lambda x,y: x+y<br />
2 >>> reduce(add, [1, 2, 3, 4, 5, 6], 0)<br />
3 21<br />
1<br />
3<br />
6<br />
10<br />
15<br />
21<br />
1 2 3<br />
4 5 6<br />
lambda x, y: x+y<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 194 / 326<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Def<strong>in</strong>ition von map<br />
Primitive für funktionales Programmieren<br />
• Können selbst implementiert werden<br />
• Ke<strong>in</strong>e Schlüsselwörter, nur vordef<strong>in</strong>iert 4 ret.append(func(ele))<br />
5 return ret<br />
mymap selbst gemacht<br />
• for-Schleife<br />
• Funktion als Parameter<br />
• Aufbau der Ergebnisliste<br />
Verwenden wie e<strong>in</strong>gebautes map<br />
• Implementierung mit mehreren<br />
Sequenzen auch e<strong>in</strong>fach möglich<br />
• Gute Hausaufgabe<br />
1 def mymap(func, seq):<br />
2 ret = []<br />
3 for ele <strong>in</strong> seq:<br />
1 >>> <strong>in</strong>k = lambda x: x+1<br />
2 >>> map(<strong>in</strong>k, [1, 2, 3])<br />
3 [2, 3, 4]<br />
4 >>> mymap(<strong>in</strong>k, [1, 2, 3])<br />
5 [2, 3, 4]<br />
6 >>> mymap(lambda x: x+1, [1, 2, 3])<br />
7 [2, 3, 4]<br />
Def<strong>in</strong>ition von filter<br />
1 def myfilter(func, seq):<br />
myfilter selbst gemacht<br />
2 ret = []<br />
• for-Schleife<br />
3 for ele <strong>in</strong> seq:<br />
• Funktion als Parameter<br />
4 if func(ele):<br />
5 ret.append(ele)<br />
• Aufbau der Ergebnisliste<br />
6 return ret<br />
Verwenden wie e<strong>in</strong>gebautes filter<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 195 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 196 / 326
Programmieren <strong>in</strong> Python<br />
Funktionale Primitive<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Def<strong>in</strong>ition von reduce<br />
List Comprehension<br />
myreduce selbst gemacht<br />
• for-Schleife<br />
• Funktion als Parameter<br />
• Aufbau des Ergebniswerts<br />
Verwenden wie e<strong>in</strong>gebautes reduce<br />
1 def myreduce(func, seq, <strong>in</strong>it=None):<br />
2 if <strong>in</strong>it == None:<br />
3 <strong>in</strong>it = seq[0]<br />
4 seq = seq[1:]<br />
5 wert = <strong>in</strong>it<br />
6 for ele <strong>in</strong> seq:<br />
7 wert = func(wert, ele)<br />
8 return wert<br />
Listentransformation<br />
• Anwendungsgebiet wie funktionales<br />
Programmieren<br />
• E<strong>in</strong>fachere Verwendung der<br />
Möglichkeiten von map und filter<br />
zusammen mit lambda und for<br />
Syntax [ for <strong>in</strong> ]<br />
1 >>> map(lambda x: x+1, [1,2,3,4])<br />
2 [2, 3, 4, 5]<br />
3 >>> [x+1 for x <strong>in</strong> [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 <strong>in</strong> [1, 5, 2, 6, 7] if x>3]<br />
8 [5, 6, 7]<br />
1 >>> add = lambda x,y: x+y<br />
• statt lambda-Ausdruck<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 />
• Durch for wird sukkzesive e<strong>in</strong><br />
Wert aus zugewiesen<br />
• Zusätzlich if , als Filter<br />
• Beliebig komb<strong>in</strong>ierbar<br />
Ausdrucksweisen<br />
• Statt verschachtelte for-Schleifen<br />
• Ähnelt math. Mengenschreibweise<br />
1 >>> [x**2 for x <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 197 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 198 / 326<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
List Comprehension – Beispiele mit Zahlen<br />
List Comprehension – Beispiele mit Text<br />
Quadratzahlen<br />
• Zahlen von 0 bis 9; 1 bis 10<br />
• Ausdruck statt Funktion<br />
Komplexe Def<strong>in</strong>ition<br />
• Mischen von Filtern und<br />
Funktionsapplikation<br />
• Aufzählen durch for<br />
Kartesisches Produkt<br />
• Sequenzen komb<strong>in</strong>ieren<br />
• Kartesisches Produkt,<br />
Vollkomb<strong>in</strong>ation<br />
• Nicht so bei funktionalem<br />
Primitiv map<br />
zip<br />
• Built<strong>in</strong>, generiert Tupel<br />
1 >>> [x for x <strong>in</strong> range(10)]<br />
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]<br />
3 >>> [x*x for x <strong>in</strong> range(1, 11)]<br />
4 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
1 >>> [(x,y) for x <strong>in</strong> range(4)<br />
2 for y <strong>in</strong> 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 <strong>in</strong> range(5) for y <strong>in</strong> 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) <strong>in</strong> 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 />
Wörter ersetzen<br />
• Kle<strong>in</strong>e 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 Str<strong>in</strong>g zusammen<br />
Datei von Zahlen zeilenweise lesen<br />
• Zeilenweise e<strong>in</strong>lesen und aufteilen<br />
(splitten)<br />
• Alle Str<strong>in</strong>gs aus Ziffern je Zeile <strong>in</strong> 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 s<strong>in</strong>d<br />
4 nicht 4 Sachen"""<br />
5 >>> pr<strong>in</strong>t " ".jo<strong>in</strong>([trans[w]<br />
6 if w <strong>in</strong> trans else w<br />
7 for w <strong>in</strong> s.split()])<br />
8 zwei Sachen und drei Sachen s<strong>in</strong>d<br />
9 nicht vier Sachen<br />
1 >>> d = "zahlen.dat"<br />
2 >>> file(d).readl<strong>in</strong>es()<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(<strong>in</strong>t, l<strong>in</strong>e.split()))<br />
7 for l<strong>in</strong>e <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 199 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 200 / 326
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Funktionale Programmierung – Zusammenfassung<br />
Vorteile<br />
• Verm<strong>in</strong>derung der Fehleranfälligkeit, zum Beispiel s<strong>in</strong>d 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 <strong>in</strong> e<strong>in</strong>er 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 E<strong>in</strong>arbeitungszeit<br />
Verbreitung<br />
• Funktionale Primitive <strong>in</strong> allen höheren Programmiersprachen zu f<strong>in</strong>den (Ruby, Perl,<br />
Lisp, C#)<br />
• Lambda-Ausdrücke s<strong>in</strong>d <strong>in</strong> C# für LINQ, <strong>in</strong> Java ab 8<br />
• MapReduce, Framework (Google) zum Suchen <strong>in</strong> riesigen Datenmenge<br />
Onl<strong>in</strong>e-Referenzen<br />
• http://www-106.ibm.com/developerworks/l<strong>in</strong>ux/library/l-prog.html<br />
• http://www.freenetpages.co.uk/hp/alan.gauld/tutfctnl.htm<br />
• . . .<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 201 / 326<br />
Module<br />
Warum Module?<br />
• Wiederverwendung von Code<br />
• Bereitstellung von allgme<strong>in</strong><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 e<strong>in</strong> Modul<br />
• C-Erweiterungen s<strong>in</strong>d Modul<br />
• Nutzen mit import, from<br />
Suche nach Dateien/Module<br />
• Umgebungsvariable PYTHONPATH<br />
• Abhängig von Wert <strong>in</strong> 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-l<strong>in</strong>ux2’,<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 202 / 326<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Def<strong>in</strong>ieren von Modulen<br />
E<strong>in</strong> Modul ist e<strong>in</strong>e Datei<br />
• Mit der Endung .py,<br />
oder vorkompiliert .pyc<br />
• In e<strong>in</strong>em Verzeichnis<br />
• Beliebiger Python-Code<br />
• Ke<strong>in</strong>e Python-Schlüsselwörter als<br />
Date<strong>in</strong>ame<br />
Im Suchpfad erreichbar<br />
• Vorgabe ist aktuelles Verzeichnis und<br />
Standard-Bibliothek von Python<br />
• sys.path<br />
me<strong>in</strong>modul.py<br />
1 # Modul me<strong>in</strong>modul, me<strong>in</strong>modul.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 pr<strong>in</strong>t 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 pr<strong>in</strong>t "me<strong>in</strong>modul geladen"<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 <strong>in</strong> Modul<br />
gebunden<br />
• * für alle Namen außer Namen,<br />
die mit e<strong>in</strong>em Unterstrich _<br />
beg<strong>in</strong>nen<br />
import [, ]*<br />
1 $ ls me<strong>in</strong>modul.py<br />
2 me<strong>in</strong>modul.py<br />
3 $ python<br />
4 >>> import me<strong>in</strong>modul<br />
5 me<strong>in</strong>modul geladen<br />
6 >>> me<strong>in</strong>modul.gruss()<br />
7 Hallo Modul Welt<br />
8 >>> me<strong>in</strong>modul.sprache=me<strong>in</strong>modul.englisch<br />
9 >>> me<strong>in</strong>modul.gruss()<br />
10 Hello module world<br />
11 >>> me<strong>in</strong>modul.sprache = englisch<br />
12 NameError: name ’englisch’ is not def<strong>in</strong>ed<br />
from import [, ]*<br />
1 >>> from me<strong>in</strong>modul import gruss<br />
2 >>> gruss()<br />
3 Hallo Modul Welt<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 203 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 204 / 326
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Module und Namensräume<br />
Ausführung beim Import<br />
• Modulanweisungen laufen nur beim<br />
ersten Import e<strong>in</strong>mal ab<br />
• Achtung bei Entwicklung, IDLE<br />
Module s<strong>in</strong>d Namensräume<br />
• E<strong>in</strong> Modul ist globaler Namensraum<br />
• Auf den Namensraum e<strong>in</strong>es Moduls<br />
können Sie zugreifen (dir(),<br />
.__dict__)<br />
1 >>> import me<strong>in</strong>modul<br />
2 me<strong>in</strong>modul geladen<br />
3 >>> dir(me<strong>in</strong>modul)<br />
4 [’__built<strong>in</strong>s__’, ’__doc__’, ’__file__’,<br />
5 ’__name__’, ’__package__’, ’deutsch’,<br />
Hauptprogramm mit ma<strong>in</strong><br />
Ziel<br />
• Ausführen e<strong>in</strong>s Code-Blocks nur, wenn<br />
es als Hauptprogramm gestartet<br />
wurde; nicht wenn es importiert wurde<br />
6 ’drucke’, ’englisch’, ’gruss’,<br />
restart führt neu aus, ohne restart<br />
• Simulieren der ma<strong>in</strong>-Funktion/Methode<br />
7 ’sprache’]<br />
werden Module nicht neu ausgeführt<br />
von C/Java<br />
8 >>> import me<strong>in</strong>modul<br />
Modulattribute<br />
9 >>> me<strong>in</strong>modul.__dict__<br />
• Häufig zum Testen e<strong>in</strong>es Moduls<br />
• Zuweisungen und<br />
10 {’drucke’: , verwendet<br />
11<br />
Funktionsdef<strong>in</strong>itionen auf der obersten ’deutsch’: ’deutsch’,<br />
Umsetzung, Idiom<br />
12 ’__built<strong>in</strong>s__’: { ....<br />
Ebene erstellen Modulattribute<br />
• Der Name des <strong>in</strong>teraktiven oder<br />
• Namen, die an Objekte gebunden s<strong>in</strong>d<br />
Haupt-Moduls ist ’__ma<strong>in</strong>__’<br />
• Test auf Name und bed<strong>in</strong>gt ausführen<br />
ma<strong>in</strong>.py<br />
1 import sys<br />
2<br />
3 def drucke(x):<br />
4 pr<strong>in</strong>t "|%s|" % x<br />
5<br />
6 if __name__ == ’__ma<strong>in</strong>__’:<br />
7 pr<strong>in</strong>t "drucker"<br />
8 for ele <strong>in</strong> sys.argv[1:]:<br />
9 drucke(ele)<br />
1 >>> import ma<strong>in</strong><br />
2 >>> ma<strong>in</strong>.drucke("hallo")<br />
3 |hallo|<br />
4 >>> ma<strong>in</strong>.drucke("hello")<br />
5 |hello|<br />
$ python ma<strong>in</strong>.py hallo hello<br />
drucker<br />
|hallo|<br />
|hello|<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 205 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 206 / 326<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Qualifikation von Namen<br />
Erzw<strong>in</strong>gen von Neuladen<br />
E<strong>in</strong>facher 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 def<strong>in</strong>ed<br />
4 >>> qual.name<br />
5 ’Name’<br />
6 >>> os.getcwd()<br />
7 NameError: name ’os’ is not def<strong>in</strong>ed<br />
8 >>> qual.os.getcwd()<br />
9 ’/home/mi/ss<strong>in</strong>n001/prog3’<br />
Import von Modulen<br />
• Module werden beim ersten Import<br />
ausgeführt<br />
• Beim zweiten importieren wird nur e<strong>in</strong><br />
neuer Namen wieder an das<br />
Modulobjekt gebunden<br />
• Zweiter Import s<strong>in</strong>nvoll um Modul im<br />
aktuellen Namensraum zu haben<br />
reload()<br />
• Lädt Modul neu, erstellt neues<br />
Modulobjekt<br />
• Wichtig beim Entwicklen, IDLE ke<strong>in</strong><br />
restart<br />
• Code-Änderungen werden erst dann<br />
wirksam<br />
m1.py<br />
1 import me<strong>in</strong>modul<br />
m2.py<br />
1 import me<strong>in</strong>modul<br />
m3.py<br />
1 import m1<br />
2 import m2<br />
3 pr<strong>in</strong>t m1.me<strong>in</strong>modul.gruss<br />
4 pr<strong>in</strong>t m2.me<strong>in</strong>modul.gruss<br />
5 m2.me<strong>in</strong>modul = reload(m2.me<strong>in</strong>modul)<br />
6 pr<strong>in</strong>t m2.me<strong>in</strong>modul.gruss<br />
1 $ python m3.py<br />
2 me<strong>in</strong>modul geladen<br />
3 <br />
4 <br />
5 me<strong>in</strong>modul geladen<br />
6 <br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 207 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 208 / 326
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Warum nicht from import *<br />
Warum nicht from import *<br />
Verunre<strong>in</strong>igung des Namensraums<br />
• Namenskonflikte möglich<br />
• Gleiche Namen <strong>in</strong> Modulen würden im<br />
importierenden Modul überschreiben,<br />
der letzte gew<strong>in</strong>nt<br />
Importieren ist Namensb<strong>in</strong>dung<br />
• Ist nicht immer was erwartet wird<br />
• Im Beispiel wird der Name sprache<br />
importiert<br />
1 >>> from me<strong>in</strong>modul import *<br />
2 me<strong>in</strong>modul geladen<br />
3 >>> gruss()<br />
4 Hallo Modul Welt<br />
5 >>> sprache = "englisch"<br />
6 >>> gruss()<br />
7 Hallo Modul Welt<br />
8 >>> import me<strong>in</strong>modul<br />
9 >>> me<strong>in</strong>modul.sprache = "englisch"<br />
10 >>> gruss()<br />
11 Hello module world<br />
1 >>> from me<strong>in</strong>modul import *<br />
2 me<strong>in</strong>modul geladen<br />
3 >>> gruss()<br />
4 Hallo Modul Welt<br />
5 >>> sprache = "englisch"<br />
6 >>> gruss()<br />
7 Hallo Modul Welt<br />
8 >>> import me<strong>in</strong>modul<br />
9 >>> me<strong>in</strong>modul.sprache = "englisch"<br />
10 >>> gruss()<br />
11 Hello module world<br />
__ma<strong>in</strong>__<br />
deutsch<br />
englisch<br />
sprache<br />
drucke<br />
gruss<br />
me<strong>in</strong>modul<br />
deutsch<br />
englisch<br />
“deutsch“<br />
“englisch“<br />
• Die Funktion gruss verwendet natürlich<br />
noch sprache im Modul me<strong>in</strong>modul<br />
from import * vermeiden<br />
import as <br />
1 >>> import me<strong>in</strong>modul as mm<br />
import as <br />
1 >>> import me<strong>in</strong>modul as mm<br />
sprache<br />
drucke<br />
gruss<br />
lambda...<br />
lambda...<br />
Wenn Modulname zu lang, as<br />
2 me<strong>in</strong>modul geladen<br />
3 >>> mm.gruss()<br />
4 Hallo Modul Welt<br />
2 me<strong>in</strong>modul geladen<br />
3 >>> mm.gruss()<br />
4 Hallo Modul Welt<br />
__ma<strong>in</strong>__<br />
me<strong>in</strong>modul<br />
mm<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 209 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 210 / 326<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Datenkapselung und Daten verstecken<br />
me<strong>in</strong>modul.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 <strong>in</strong> Python, ke<strong>in</strong><br />
4 if s <strong>in</strong> [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 me<strong>in</strong>modulgross 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 />
• Ke<strong>in</strong>e Modulattribute ändern, nur lesen >>> mm.gruss()<br />
6 Hello module world<br />
• Nur Funktionen verwenden<br />
7 >>> mm.andere_sprache("portugiesisch")<br />
• Ke<strong>in</strong>e Funktionen mit _ am Anfang 8 Exception: Sprache portugiesisch<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 211 / 326<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 e<strong>in</strong> Ordner die Datei<br />
__<strong>in</strong>it__.py enthält, dann ist der<br />
Ordner e<strong>in</strong> Package<br />
• __<strong>in</strong>it__.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 str<strong>in</strong>g<br />
2 def machkle<strong>in</strong>(s):<br />
3 return s.lower()<br />
paket/__<strong>in</strong>it__.py<br />
1 import a<br />
2 from a import s<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 212 / 326
Programmieren <strong>in</strong> Python<br />
List Comprehension<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<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 str<strong>in</strong>g<br />
7 (’hallo’, ’hallo’)<br />
2 def machkle<strong>in</strong>(s):<br />
8 >>> paket.b<br />
3 return s.lower()<br />
9 AttributeError: ’module’ object has<br />
10 no attribute ’b’<br />
paket/__<strong>in</strong>it__.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.str<strong>in</strong>g.lower("hallo")<br />
15 ’hallo’<br />
Objektorientierung <strong>in</strong> Python<br />
Ähnlich zu Java<br />
• Schlüsselworte, Referenzsemantik<br />
• Attribute, Vererbung, Polymorphismus<br />
• E<strong>in</strong>fach, Sprache mit OO konzipiert<br />
Unterschiede, neue Features<br />
• Dynamische Attribute, Attributsuche<br />
• Mehrfachvererbung, ke<strong>in</strong>e Schnittstellen<br />
• Kapselung (Komposition) nur per Konvention,<br />
aber Properties<br />
• Operatorenüberladung, Duck-Typ<strong>in</strong>g (reagieren auf<br />
Index-Zugriff, Ausgabe, Slicen)<br />
• Selbst erstellte Klassen verhalten sich wie<br />
e<strong>in</strong>gebaute Typen<br />
• Alles! ist e<strong>in</strong> Objekt (Zahlen, Module, . . . )<br />
1 >>> i=3<br />
2 >>> type(i)<br />
3 <br />
4 >>> is<strong>in</strong>stance(i, <strong>in</strong>t)<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(<strong>in</strong>t, object)<br />
16 True<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 213 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 214 / 326<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Klassen<br />
Klassendef<strong>in</strong>ition<br />
• class: Schlüsselwort<br />
• : Name für die Klasse<br />
• object: Wurzelklasse, immer angeben<br />
• : Dokumentationsstr<strong>in</strong>g<br />
• : Funktionsdef<strong>in</strong>itionen für Methoden<br />
Besonderheiten<br />
• Erstes Methodenargument ist immer Instanzobjekt<br />
• Per Konvention der Name self, <strong>in</strong> Java wäre es this<br />
• Spezielle Methode __<strong>in</strong>it__ statt Konstruktor<br />
• Attribute s<strong>in</strong>d Klassenattribute und nicht, wie von<br />
Java erwartet, Instanzattribute<br />
• Instanzattribute dynamisch (__<strong>in</strong>it__) <strong>in</strong><br />
Namensraum self schreiben<br />
class (object):<br />
[]<br />
<br />
klasse.py<br />
1 class A(object):<br />
2 "E<strong>in</strong>e Klasse A"<br />
3 def __<strong>in</strong>it__(self):<br />
4 self.a = 17<br />
5 def <strong>in</strong>ca(self):<br />
6 self.a += 1<br />
7 pr<strong>in</strong>t A<br />
$ python klasse.py<br />
<br />
Ausführung erzeugt<br />
Klassenobjekt (Klassen<br />
s<strong>in</strong>d Objekte!), b<strong>in</strong>den<br />
Klassenname an<br />
Klassenobjekt<br />
Klassendef<strong>in</strong>ition – 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 Def<strong>in</strong>ition<br />
• self ist Namensraum e<strong>in</strong>er Instanz<br />
• Weitere Argumente bei Methoden<br />
erlaubt<br />
• Manipulation der Instanzattribute <strong>in</strong><br />
self sollte nur durch Methoden<br />
erfolgen<br />
• Ke<strong>in</strong>e 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 __<strong>in</strong>it__(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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 215 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 216 / 326
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Generieren und Nutzen von Instanzen<br />
Vererbung und Mehrfachvererbung<br />
Klassendef<strong>in</strong>ition<br />
• Klassenname ist Name gebunden an<br />
Klassenobjekt<br />
• Im Beispiel Stack <strong>in</strong> stack.py<br />
Instanziierung<br />
• Neue Instanz durch Aufruf<br />
Klassennamen (ke<strong>in</strong> new)<br />
• Implizit wird __<strong>in</strong>it__ 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 />
Vererbung<br />
• Superklassen <strong>in</strong> Klammern dah<strong>in</strong>ter<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 <strong>in</strong> aktueller Klasse<br />
• Dann <strong>in</strong> Superklassen wie def<strong>in</strong>iert<br />
• Erst alle Superklassen der<br />
Superklassen<br />
• Kurz: von l<strong>in</strong>ks nach rechts,<br />
Tiefensuche*<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 <br />
5 >>> s.push(1); s.push(2); s.push(3)<br />
6 >>> s.peek(2)<br />
7 3<br />
8 >>> s.peek(0)<br />
9 1<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 217 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 218 / 326<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Klassen- und Instanzvariablen<br />
Klassen- und Instanzvariablen – Attributsuche<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 pr<strong>in</strong>t "Klasse", K.verbose<br />
• Entspricht Instanzvariablen <strong>in</strong> Java<br />
7 pr<strong>in</strong>t "Instanz", self.verbose<br />
Klassenvariablen<br />
• Initialisierung als Attribute<br />
• In durch Klassennamen<br />
aufgespannten Namensraum<br />
• Entspricht static Variablen <strong>in</strong> Java<br />
• Achtung: Syntax wie Instanzvariablen<br />
<strong>in</strong> Java<br />
1 class K(object):<br />
2 verbose = 1<br />
3 def __<strong>in</strong>it__(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 />
Suchordnung<br />
• Erst Instanz, dann Klasse, dann<br />
Superklassen<br />
Suche <strong>in</strong> self<br />
• Wenn ke<strong>in</strong>e Instanzvariable vorliegt,<br />
wird die der Klasse gelesen,<br />
Zeile 2<br />
Zur Laufzeit änderbar<br />
• Instanzvariable zur Laufzeit<br />
h<strong>in</strong>zufü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 __<strong>in</strong>it__(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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 219 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 220 / 326
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Klassenmethoden<br />
Dekorator<br />
Statische Methoden<br />
• Klassenmethode, bezieht sich nicht<br />
auf Instanz, <strong>in</strong> Java static<br />
• Syntax: Dekorator @staticmethod<br />
• Ke<strong>in</strong> 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 __<strong>in</strong>it__(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 />
Dekoratorfunktion<br />
• Funktion, die m<strong>in</strong>destens e<strong>in</strong>e<br />
Funktion als Argument hat und e<strong>in</strong>e<br />
Funktion zurückgibt; e<strong>in</strong>packen<br />
• Ziel: Verhalten und Syntax e<strong>in</strong>er<br />
Funktion ändern<br />
• Beispiele<strong>in</strong>satz: statische Methoden<br />
• Beispiel: statisch <strong>in</strong> Zeilen 6-8, <strong>in</strong><br />
Python >> k = K()<br />
2 >>> statisch(3)<br />
3 >>> K.zaehle<br />
4 4<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 223 / 326<br />
Klassen und Instanzen s<strong>in</strong>d 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 __<strong>in</strong>it__(self):<br />
4 self.x = 1<br />
5 class K2(K1):<br />
6 x = 3<br />
7 def __<strong>in</strong>it__(self):<br />
8 K1.__<strong>in</strong>it__(self)<br />
9<br />
• def f(self):<br />
Suche erst <strong>in</strong> aktueller Instanz,<br />
10 self.x = 2<br />
be<strong>in</strong>haltet was durch Superklassen an<br />
11 def showx(self):<br />
Instanz geändert wurde,<br />
12 pr<strong>in</strong>t self.x,<br />
dann erst <strong>in</strong> Klassenscope<br />
13 k = K2(); k.showx()<br />
• Nicht im def<strong>in</strong>ierenden 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 224 / 326
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Klassen, Selbstbeobachtung<br />
Properties statt Getter und Setter<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 __<strong>in</strong>it__(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__’, ’__<strong>in</strong>it__’, ’__module__’,<br />
13 ’__new__’, ’__reduce__’, ’__reduce_ex__’,<br />
14 ’__repr__’, ’__setattr__’, ’__sizeof__’,<br />
15 ’__str__’, ’__subclasshook__’, ’__weakref__’,<br />
16 ’verbose’]<br />
Durchgriff auf Attribute<br />
• Ist <strong>in</strong> Python <strong>in</strong> Ordnung<br />
• Ke<strong>in</strong>e Getter und Setter<br />
• Man kann nachträglich ändern und<br />
Kontrolle wieder erlangen<br />
Properties<br />
• Eigentliches Attribut verstecken, _ am<br />
Namensanfang als H<strong>in</strong>weis<br />
• Def<strong>in</strong>ition Getter, Setter und Löschen<br />
• Def<strong>in</strong>ition des Attributs mit<br />
property(get, set, delete, doc)<br />
1 class Name(object):<br />
2<br />
3 def __<strong>in</strong>it__(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 <strong>in</strong> oktypes:<br />
12 msg = "vorname ke<strong>in</strong> Str<strong>in</strong>g"<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 Str<strong>in</strong>g/Unicode")<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 225 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 226 / 326<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> 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 ke<strong>in</strong> Str<strong>in</strong>g<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 />
Überladen von Operatoren – Motivation<br />
Ziel<br />
• Rechnen Modulo e<strong>in</strong>er 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 <strong>in</strong>tuitiv<br />
Wunsch<br />
• Benutzen der Modulo-Instanzen wie<br />
e<strong>in</strong>gebaute Zahlen<br />
1 class Modulo(object):<br />
2 "Rechnen modulo e<strong>in</strong>er Zahl"<br />
3 def __<strong>in</strong>it__(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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 227 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 228 / 326
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Überladen von Operatoren – Umsetzung<br />
Überladbare Operatoren – Auszug<br />
Vordef<strong>in</strong>ierte Funktionsnamen<br />
• Werden gerufen bei Anwendung von<br />
Operatoren<br />
• Beg<strong>in</strong>nen und enden mit zwei<br />
Unterstrichen<br />
• Def<strong>in</strong>ition neuer Operatoren nicht<br />
möglich<br />
Beispiele<br />
• __repr__: Repräsentation bei<br />
<strong>in</strong>teraktiver Ausgabe, es wird Str<strong>in</strong>g<br />
erwartet, Java’s toStr<strong>in</strong>g ist __str__<br />
• __add__: Wird gerufen bei<br />
l<strong>in</strong>ksseitigem + Operator<br />
Achtung: E<strong>in</strong>gebautes + liefert immer<br />
e<strong>in</strong> 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 />
• __<strong>in</strong>it__: Konstruktorersatz, __<strong>in</strong>it__ der Superklasse nicht automatisch gerufen<br />
• __del__: Destruktorersatz, beim expliziten Löschen und bei Garbage-Collection<br />
• __add__, __or__: Operator +, |<br />
• __repr__: Drucken (pr<strong>in</strong>t), Konvertierung<br />
• __call__: Funktionsaufruf ()<br />
• __getattr__, __getattribute__: Qualifikation<br />
• __getitem__: Indizierung, auch von <strong>in</strong>-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 <strong>in</strong> der Dokumentation<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 229 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 230 / 326<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Von e<strong>in</strong>gebauten Klassen ableiten<br />
Iteratoren für eigene Klassen<br />
Beispiel eigenes Wörterbuch<br />
• Verhalten wie dict, aber nur Str<strong>in</strong>gs<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 Str<strong>in</strong>g 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["e<strong>in</strong>s"] = 2<br />
4 >>> dic<br />
5 {1: 2, ’e<strong>in</strong>s’: 2}<br />
6 >>> strdic = strdict()<br />
7 >>> strdic[1] = 2<br />
8 AttributeError: nur Str<strong>in</strong>g als Key<br />
9 >>> strdic["e<strong>in</strong>s"] = 2<br />
10 >>> strdic<br />
11 {’e<strong>in</strong>s’: 2}<br />
for-Kontrollstruktur<br />
• E<strong>in</strong>faches Iterieren über Sequenzen<br />
• Funktioniert mit Iterator-Objekt<br />
• next gibt nächstes Element zurück<br />
• Ausname StopIteration, wenn ke<strong>in</strong><br />
Element mehr verfügbar<br />
• Ähnlich zu Java<br />
iter-Methode, e<strong>in</strong>gebaut<br />
• Holt von Objekt Iterator, wenn möglich<br />
• Implizit und explizit verwendbar<br />
• Beispiel mit Listen<br />
1 >>> l = [1, 2, 3]<br />
2 >>> lis = [1, 2, 3]<br />
3 >>> for ele <strong>in</strong> lis:<br />
4 pr<strong>in</strong>t ele<br />
5 1<br />
6 2<br />
7 3<br />
1 >> lis = [1, 2, 3]<br />
2 >>> it = iter(l)<br />
3 >>> it<br />
4 <br />
5 >>> it.next()<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 231 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 232 / 326
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Iteratoren für eigene Klassen – Instanz selbst<br />
Iteratoren für eigene Klassen – Iterator-Klasse<br />
Selbst implementieren <strong>in</strong> der Klasse<br />
• Überladen von __iter__<br />
• Erwartet Iterator-Objekt<br />
Bewertung<br />
• Zum Beispiel sich selbst, wenn<br />
Methode next def<strong>in</strong>iert ist<br />
• Ke<strong>in</strong>e Schnittstellen, Duck-Typ<strong>in</strong>g<br />
• E<strong>in</strong>fach zu realisieren<br />
1 class Iterselbst(object):<br />
2 def __<strong>in</strong>it__(self):<br />
3 self.lis = [1,2,3]<br />
4 def __iter__(self):<br />
5 self.<strong>in</strong>dex = 0<br />
6 return self<br />
7 def next(self):<br />
8 if self.<strong>in</strong>dex >= len(self.lis):<br />
9 raise StopIteration<br />
10 self.<strong>in</strong>dex += 1<br />
11<br />
• return self.lis[self.<strong>in</strong>dex-1]<br />
Nachteil: Nur e<strong>in</strong> Iterator gleichzeitig je<br />
Instanz, da aktueller Zustand nur<br />
1 >>> its = Iterselbst()<br />
e<strong>in</strong>mal <strong>in</strong> der Instanz gespeichert ist<br />
2 >>> for ele <strong>in</strong> its:<br />
3 pr<strong>in</strong>t 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 />
Separate Iterator-Klasse<br />
• Neu def<strong>in</strong>ierte Iterator-Klasse itk<br />
• Kann durchaus im normalen<br />
Codeblock dynamisch erfolgen<br />
• Instanz der Klasse <strong>in</strong>itialisieren 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 __<strong>in</strong>it__(self):<br />
3 self.lis = [1,2,3]<br />
4 def __iter__(self):<br />
5 class itk(object):<br />
6 def __<strong>in</strong>it__(self, lis):<br />
7 self.<strong>in</strong>dex = 0<br />
8 self.lis = lis[:]<br />
9 def next(self):<br />
10 if self.<strong>in</strong>dex >= len(self.lis):<br />
11 raise StopIteration<br />
12 self.<strong>in</strong>dex += 1<br />
13 return self.lis[self.<strong>in</strong>dex-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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 233 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 234 / 326<br />
Programmieren <strong>in</strong> Python<br />
Objektorientierung<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Iteratoren für eigene Klassen – Iterator von Standardtyp<br />
Generatoren – Motivation<br />
Iterator von Standardtyp verwenden<br />
• Standardtyp nehmen oder aufbauen<br />
• Davon Iterator zurückgeben<br />
Bewertung<br />
• E<strong>in</strong>fach, robust; bevorzugen<br />
<strong>in</strong> Tests<br />
• Sobald Iterator implementiert ist, ist<br />
auch automatisch der <strong>in</strong>-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 __<strong>in</strong>it__(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 <strong>in</strong> its, 17 <strong>in</strong> its<br />
3 (True, False)<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?: E<strong>in</strong>fache 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 />
Programmieren<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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 235 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 236 / 326
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Generatoren – Konzept<br />
Generatoren <strong>in</strong> Python<br />
• yield statt return <strong>in</strong> Funktion<br />
• Nur e<strong>in</strong>s von beiden <strong>in</strong> 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 />
e<strong>in</strong>gefroren<br />
• Bei jedem next zum nächsten Wert<br />
• StopIteration am Ende<br />
Vorteile<br />
• Ke<strong>in</strong>e großen Datenstrukturen im<br />
Speicher halten<br />
• Natürliche Realisierung von Iteratoren<br />
• Grundlage für die meisten Built<strong>in</strong>s<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 237 / 326<br />
Generatoren – Grundlage für viele Built<strong>in</strong>s<br />
Beispiel: E<strong>in</strong>e offene Datei ist e<strong>in</strong><br />
Generator, der die Zeilen <strong>in</strong> 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 />
10 ’ i += 1\n’<br />
11 >>> f.next()<br />
12 StopIteration<br />
Beispiel: Das Ergebnis e<strong>in</strong>es Aufrufs von<br />
reversed ist e<strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 238 / 326<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Programmieren <strong>in</strong> 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 e<strong>in</strong>e Liste daraus,<br />
läuft ewig für unendliche Generatoren<br />
• Verwendung von for möglich und<br />
s<strong>in</strong>nvoll auch bei potentiell unendlich<br />
lange laufenden Generatoren<br />
• Abbruch mit StopIteration<br />
• Abbruch nicht notwendig<br />
1 def hoch4():<br />
2 for ele <strong>in</strong> quads():<br />
3 yield ele**2<br />
1 sum = 0<br />
2 for quad <strong>in</strong> quads():<br />
3 sum += quad<br />
4 if sum > 1000000:<br />
5 break<br />
6 pr<strong>in</strong>t sum # 1005720<br />
1 def nquads(n):<br />
2 for i <strong>in</strong> range(1, n+1):<br />
3 yield i**2<br />
1 def nquads(n):<br />
2 grenze = n**2<br />
3 for ele <strong>in</strong> 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 />
Generatoren – Fibonacci<br />
Folge der Fibonacci-Zahlen<br />
• Startwerte, zwei Mal die E<strong>in</strong>s<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 e<strong>in</strong>frieren<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 <strong>in</strong> range(10):<br />
3 pr<strong>in</strong>t f.next(),<br />
4 1 1 2 3 5 8 13 21 34 55<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 239 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 240 / 326
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Generatoren – Baum traversieren<br />
Generatoren – itertools, Slicen<br />
Baum<br />
• Knoten als Drei-Tupel, Wert ist Str<strong>in</strong>g<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 />
b<strong>in</strong>tree<br />
d<br />
b<br />
e<br />
a<br />
c<br />
1 def <strong>in</strong>order(node):<br />
2 if node == None:<br />
3 raise StopIteration<br />
4 left, value, right = node<br />
5 for valueleft <strong>in</strong> <strong>in</strong>order(left):<br />
6 yield valueleft<br />
7 yield value<br />
8 for valueright <strong>in</strong> <strong>in</strong>order(right):<br />
9 yield valueright<br />
1 b<strong>in</strong>tree = (<br />
2 ((None, "d", None),<br />
3 "b",<br />
4 (None, "e", None)),<br />
5 "a",<br />
6 (None, "c", None))<br />
1 >>> for value <strong>in</strong> <strong>in</strong>order(b<strong>in</strong>tree):<br />
2 pr<strong>in</strong>t value,<br />
3 d b e a c<br />
Generatoren s<strong>in</strong>d ke<strong>in</strong>e Sequenzen<br />
• Generatoren s<strong>in</strong>d potentiell unendlich<br />
• Umformung <strong>in</strong> Listen und Slic<strong>in</strong>g nicht<br />
s<strong>in</strong>nvoll<br />
• Standard-Features von Sequenzen<br />
(Slic<strong>in</strong>g, 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 Programmieren<br />
8<br />
Slicen mit islice<br />
>>> list(islice(q, 0, 10))<br />
9 [121, 144, 169, 196, 225, 256, 289, 324, 361, 4<br />
• Aufruf von islice mit start, stop, step<br />
10 >>> list(islice(q, 0, 10))<br />
• Nachbau Funktionalität<br />
11 [441, 484, 529, 576, 625, 676, 729, 784, 841, 9<br />
[start:stop:step]<br />
1 >>> list(quads())<br />
2 ... # 1 GB, 2 GB, 3 GB, ...<br />
3 ... # ca. 3 M<strong>in</strong>uten 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 />
12 >>> list(islice(quads(), 0, 10))<br />
13 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 241 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 242 / 326<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Programmieren <strong>in</strong> Python<br />
Generatoren<br />
Generatoren – itertools, Funktional Progammieren<br />
Funktional Programmieren<br />
• Etwas für alle Elemente e<strong>in</strong>er<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 <strong>in</strong> 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 />
* Ke<strong>in</strong>e 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 pend<strong>in</strong>g... :-)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 243 / 326<br />
Generatoren – Generator Expressions<br />
List Comprehension für<br />
Generatoren<br />
• List Comprehension direkt<br />
wieder nicht s<strong>in</strong>nvoll, 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 <strong>in</strong> quads() if i%2 == 0)<br />
Mächtiges elegantes Konzept,<br />
nutzen!<br />
1 >>> gq = (i**2 for i <strong>in</strong> 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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 244 / 326
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Ausnahmen<br />
Ausnahmen fangen – Schema<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 allgeme<strong>in</strong>en Kontrollfluss verwendet werden<br />
Ausnahmen <strong>in</strong> Python<br />
• In Sprache <strong>in</strong>tegriert, e<strong>in</strong>fach zu verwenden<br />
• Ähnlich zu Java<br />
Syntax<br />
• try, else, except, f<strong>in</strong>ally: Rahmen für Code-Strecken mit potentiellen<br />
Ausnahmen, Fangen und Verarbeiten der Ausnahmen<br />
• raise: Werfen von Ausnahmen<br />
• assert: Wie <strong>in</strong> C<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 245 / 326<br />
• im try-Block ausführen<br />
• Falls Ausführung Ausnahme wirft mit<br />
expect fangen<br />
• E<strong>in</strong>e oder mehrere Ausnahmen als<br />
Tupel möglich<br />
• Mehrere except möglich<br />
• Mit optionalem an Ausnahme-Instanz<br />
an b<strong>in</strong>den<br />
• Falls Ausnahme gefangen<br />
entsprechenden except-Block<br />
ausführen<br />
• else-Block (optional) falls ke<strong>in</strong>e<br />
Ausnahme geworfen wurde<br />
• f<strong>in</strong>ally-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 />
f<strong>in</strong>ally:<br />
<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 246 / 326<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Ausnahmen fangen – Beispiele, except, else<br />
Ausnahmen fangen – Beispiele, f<strong>in</strong>ally<br />
1 >>> 3/0<br />
2 ZeroDivisionError: <strong>in</strong>teger div.. by zero2 3/0<br />
3 >>> try:<br />
4 3/0<br />
5 except ZeroDivisionError:<br />
6 pr<strong>in</strong>t "nicht durch Null"<br />
7 nicht durch Null<br />
8 >>> try:<br />
9 3/0<br />
10 except ZeroDivisionError as e:<br />
11 pr<strong>in</strong>t type(e), e<br />
12 <br />
13 <strong>in</strong>teger division or modulo by zero<br />
14 >>> try:<br />
15 3/0<br />
16 except IndexError:<br />
17 pr<strong>in</strong>t "IE"<br />
18 except ZeroDivisionError:<br />
19 pr<strong>in</strong>t "ZDE"<br />
20 ZDE<br />
1 >>> try:<br />
3 except ZeroDivisionError:<br />
4 pr<strong>in</strong>t "ZDE"<br />
5 else:<br />
6 pr<strong>in</strong>t "OK"<br />
7 ZDE<br />
8 >>> try:<br />
9 3/1<br />
10 except ZeroDivisionError:<br />
11 pr<strong>in</strong>t "ZDE"<br />
12 else:<br />
13 pr<strong>in</strong>t "OK"<br />
14 3<br />
15 OK<br />
ZeroDivisionError, built<strong>in</strong> Ausnahmetyp<br />
Nicht gefangene Ausnahme propagiert<br />
zum TopLevel<br />
1 >> try:<br />
2 ... 3/0<br />
3 ... except ZeroDivisionError:<br />
4 ... pr<strong>in</strong>t "ZDE"<br />
5 ... f<strong>in</strong>ally:<br />
6 ... pr<strong>in</strong>t "immer"<br />
7 ...<br />
8 ZDE<br />
9 immer<br />
10 >>> try:<br />
11 ... 3/1<br />
12 ... except ZeroDivisionError:<br />
13 ... pr<strong>in</strong>t "ZDE"<br />
14 ... f<strong>in</strong>ally:<br />
15 ... pr<strong>in</strong>t "immer"<br />
16 ...<br />
17 3<br />
18 immer<br />
1 >>> try:<br />
2 ... 3/0<br />
3 ... except IndexError:<br />
4 ... pr<strong>in</strong>t "IE"<br />
5 ... f<strong>in</strong>ally:<br />
6 ... pr<strong>in</strong>t "immer"<br />
7 ...<br />
8 immer<br />
9 ZeroDivisionError: <strong>in</strong>teger division<br />
10 or modulo by zero<br />
f<strong>in</strong>ally wird immer ausgeführt<br />
Be<strong>in</strong>haltet meist Aufräumaktionen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 247 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 248 / 326
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Programmieren <strong>in</strong> 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 <strong>in</strong> Datei<br />
8 return count<br />
• 0, wenn Datei nicht vorhanden<br />
1 def countl<strong>in</strong>esfile(filename):<br />
2 try:<br />
3 count = 0<br />
4 for _ <strong>in</strong> file(filename):<br />
1 >>> countl<strong>in</strong>esfile("/etc/passwd")<br />
2 44<br />
3 >>> countl<strong>in</strong>esfile("/GIBTESNICHT")<br />
4 0<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 249 / 326<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 />
10 | | +-- Float<strong>in</strong>gPo<strong>in</strong>tError<br />
11 | | +-- OverflowError<br />
12 | | +-- ZeroDivisionError<br />
13 | +-- AssertionError<br />
14 | +-- AttributeError<br />
15 | +-- EnvironmentError<br />
16 | | +-- IOError<br />
17 | | +-- OSError<br />
18 | | +-- W<strong>in</strong>dowsError (W<strong>in</strong>dows)<br />
19 | | +-- VMSError (VMS)<br />
20 | +-- EOFError<br />
21 | +-- ImportError<br />
22 | +-- LookupError<br />
23 | | +-- IndexError<br />
24 | | +-- KeyError<br />
25 | +-- MemoryError<br />
26 | +-- NameError<br />
27 | | +-- 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 +-- Warn<strong>in</strong>g<br />
15 +-- DeprecationWarn<strong>in</strong>g<br />
16 +-- Pend<strong>in</strong>gDeprecationWarn<strong>in</strong>g<br />
17 +-- RuntimeWarn<strong>in</strong>g<br />
18 +-- SyntaxWarn<strong>in</strong>g<br />
19 +-- UserWarn<strong>in</strong>g<br />
20 +-- FutureWarn<strong>in</strong>g<br />
21 +-- ImportWarn<strong>in</strong>g<br />
22 +-- UnicodeWarn<strong>in</strong>g<br />
23 +-- BytesWarn<strong>in</strong>g<br />
Eigene Ausnahmeklassen passend<br />
ableiten<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 250 / 326<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Ausnahmen werfen<br />
Ausnahmen mit assert<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 e<strong>in</strong><br />
Instanzen oder Klassen werfen<br />
• Instanz um Daten mitzugeben<br />
• Häufig s<strong>in</strong>d Daten e<strong>in</strong> Str<strong>in</strong>g<br />
Vordef<strong>in</strong>ierte Ausnahmen verwendbar<br />
1 >>> raise Exception("nix geht")<br />
2 Exception: nix geht<br />
1 >>> class Me<strong>in</strong>eAusnahme(object):<br />
2 pass<br />
3 >>> raise Me<strong>in</strong>eAusnahme<br />
4 TypeError: exceptions must be old-style<br />
5 classes or derived from<br />
6 BaseException, not type<br />
7<br />
8 >>> class Me<strong>in</strong>eAusnahme(Exception):<br />
9 pass<br />
10 >>> raise Me<strong>in</strong>eAusnahme<br />
11 __ma<strong>in</strong>__.Me<strong>in</strong>eAusnahme<br />
12<br />
13 >>> try:<br />
14 msg="Weil es nicht geht"<br />
15 raise Me<strong>in</strong>eAusnahme(msg)<br />
16 except Me<strong>in</strong>eAusnahme as <strong>in</strong>st:<br />
17 pr<strong>in</strong>t "Warum?", <strong>in</strong>st<br />
18 Warum? Weil es nicht geht<br />
Zusicherungen mit assert<br />
• : e<strong>in</strong> Test<br />
• Sobald Test äquivalent zu False<br />
evaluiert, AssertionError<br />
Optimierung<br />
• Gesteuert durch globale Variable<br />
__debug__<br />
• Beim Übersetzen mit -O wird<br />
__debug__ = False gesetzt bzw. der<br />
Bytecode komplett entfernt<br />
Benutzung<br />
• Schleifen<strong>in</strong>varianten, Vor- und<br />
Nachbed<strong>in</strong>gungen<br />
• Frühzeitige Fehlererkennung<br />
• Lauffähige Dokumentation<br />
assert , <br />
if __debug__:<br />
if not :<br />
raise AssertionError()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 251 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 252 / 326
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Programmieren <strong>in</strong> Python<br />
Ausnahmen<br />
Ausnahmen mit assert – Beispiel<br />
Zerlegen von e<strong>in</strong>em Str<strong>in</strong>g<br />
• Wir gehen davon aus, dass der Str<strong>in</strong>g<br />
immer genau e<strong>in</strong>en 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 <strong>in</strong>dex out of range<br />
9 >>> zerlege_safe("a")<br />
10 assert len(l) == 2, l<br />
11 AssertionError: [’a’]<br />
Ausnahmen statt “Check then Act”-Fehler<br />
Aufgabe<br />
• Überprüfe die Existenz e<strong>in</strong>er Datei<br />
• Falls vorhanden, erste Zeile zurück<br />
• Falls nicht vorhanden, hart beenden<br />
• Es darf ke<strong>in</strong> 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 />
• Ke<strong>in</strong> Problem, sobald die Datei<br />
geöffnet werden konnte, ist sie da<br />
E<strong>in</strong> 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 pr<strong>in</strong>t "file not found"<br />
4 sys.exit(-1)<br />
5 return file(fname).readl<strong>in</strong>e()<br />
1 def get_status(fname):<br />
2 try:<br />
3 return file(fname).readl<strong>in</strong>e()<br />
4 except (IOError, OSError) as e:<br />
5 pr<strong>in</strong>t "problem; exit<strong>in</strong>g: "+str(e)<br />
6 sys.exit(-1)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 253 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 254 / 326<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Bibliotheken – Module <strong>in</strong> der Standardbibliothek<br />
Python-Bibliotheken – viel im Standard<br />
• Als Module/Pakete verfügbar<br />
• Breites Angebot, “Batteries <strong>in</strong>cluded”,<br />
ausführlich dokumentiert<br />
Beispiele:<br />
• os: Systemnah, Verzeichnisse/Dateien<br />
sys: Python-Umgebung<br />
• unittest: Unit Test<strong>in</strong>g<br />
pickle: Objektpersistenz<br />
urllib, cgi, imap, ftp, http: Web,<br />
Internet Protokolle<br />
PIL: Bildbearbeitung (nicht standard)<br />
turtle: E<strong>in</strong>fachstgraphik, Tk<strong>in</strong>ter<br />
Tk<strong>in</strong>ter, 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/ss<strong>in</strong>n001’<br />
4 >>> os.chdir("/usr/share/games/fortunes")<br />
5 >>> os.getcwd()<br />
6 ’/usr/share/games/fortunes’<br />
7 >>> [x for x <strong>in</strong> 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.f<strong>in</strong>dall(r’ab+c’, "abbcdsabcab")<br />
16 [’abbc’, ’abc’]<br />
Unit Test<strong>in</strong>g<br />
Ziel<br />
• Funktionalitäten fe<strong>in</strong>granular testen<br />
• Automatisierung, e<strong>in</strong>fache 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.ma<strong>in</strong>()<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__ == ’__ma<strong>in</strong>__’:<br />
unittest.ma<strong>in</strong>()<br />
Anpassbar, flexibel, weitere Optionen<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 255 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 256 / 326
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Unit Test<strong>in</strong>g – Beispiel<br />
Beispieltest “Ist Primzahl?”<br />
• Importieren Modul<br />
• Zu testende Funktion is_prim,<br />
meist <strong>in</strong> anderem Modul<br />
• Testfunktionen<br />
• Start der Tests<br />
Ausgabe<br />
..<br />
• Zwei Tests ok durchgelaufen<br />
-------------------------------<br />
Ran 2 tests <strong>in</strong> 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 <strong>in</strong> 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__ == ’__ma<strong>in</strong>__’:<br />
20 unittest.ma<strong>in</strong>()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 257 / 326<br />
Pickle – E<strong>in</strong>fache Objektpersistenz<br />
Ziel<br />
• Serialisierung von Objekt<strong>in</strong>stanzen<br />
• Plattform- und versionsunabhängig<br />
• Ke<strong>in</strong> Persistenzframework<br />
Umsetzung – pickle<br />
• Für e<strong>in</strong>gebaute 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 __<strong>in</strong>it__(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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 258 / 326<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Pickle – E<strong>in</strong>lesen<br />
Beispiel<br />
• Referenzen, auch zirkuläre,<br />
werden richtig wiederhergestellt<br />
• Instanzen von Objekten werden<br />
richtig wieder <strong>in</strong>stanziiert<br />
• Klasse/Modul muss verfügbar<br />
se<strong>in</strong>, wird nicht gepickelt<br />
• E<strong>in</strong>laden über import muss<br />
klappen<br />
Erweiterungen<br />
• Pickeln von Instanzen über<br />
Methoden bee<strong>in</strong>flussbar<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’: ’e<strong>in</strong>s’})<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 259 / 326<br />
Internetdaten verarbeiten<br />
• rfc822, mimetools, mimetypes, mailcap, imaplib, mailbox, smtplib, nntplib:<br />
Email- und News-spezifische Bibliotheken<br />
• uu, b<strong>in</strong>ascii: 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 onl<strong>in</strong>e\n\n ’<br />
6 >>> hl = re.f<strong>in</strong>dall(r’(.*?)’, s)<br />
7 >>> for t <strong>in</strong> [t for t <strong>in</strong> hl if "Android" <strong>in</strong> t]: pr<strong>in</strong>t t<br />
8 Unzuverlaessige Trojaner-Warnungen durch Android 4.2<br />
9 LTE-Smartphone mit Android 4.0 von HTC<br />
10 Java-IDE IDEA 12: neue Oberflaeche, neuer Compiler-Modus, neuer Android-Designer<br />
11 G<strong>in</strong>gerbread bleibt die am meisten benutzte Android-Version<br />
12 Aktualisierte Maps-API fuer Android-Entwickler<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 260 / 326
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Turtle Graphics<br />
Bildbearbeitung mit PIL<br />
Turtle Graphics<br />
• E<strong>in</strong>fache Graphiken wie mit e<strong>in</strong>em Stift<br />
erstellen, “Logo, Programm<strong>in</strong>g 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 <strong>in</strong> range(100):<br />
10 goto(i, i**2/100.)<br />
Python Imag<strong>in</strong>g Library (PIL)<br />
• C-Erweiterung<br />
• Nicht im Standard<br />
• E<strong>in</strong>fach, 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 />
10 >>> im4=im.filter(ImageFilter.FIND_EDGES)<br />
11 >>> im4.show()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 261 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 262 / 326<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Spiele mit pygame<br />
Spiele Programmieren mit pygame<br />
• Komb<strong>in</strong>ation 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.<strong>in</strong>it()<br />
4 bild = pygame.image.load("hsrm.png")<br />
5 groesse = breite, hoehe = 800, 600<br />
1 if __name__ == ’__ma<strong>in</strong>__’:<br />
2 ma<strong>in</strong>()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 263 / 326<br />
pygame – E<strong>in</strong> Bild bewegt sich<br />
Bewegung: bewege<br />
• Innerhalb e<strong>in</strong>es Rechtecks<br />
• Bei Wand (Ende Rechteck),<br />
ändere Bewegungsrichtung<br />
(wieder zurück)<br />
• Bewege!<br />
Anzeige, Animation: ma<strong>in</strong><br />
• Initialisierung Bildschirm,<br />
Bewegungsrichtung<br />
• GameLoop<br />
• Bearbeite (ignoriere) Events<br />
• H<strong>in</strong>tergrund<br />
• Bewege Bild<br />
• Bild auf (virtuellen) Bildschirm<br />
• Br<strong>in</strong>ge 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 ma<strong>in</strong>():<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 <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 264 / 326
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
pygame – Besser, Klasse für Spielobjekte<br />
pygame – Besser, Loop<br />
Logo-Klasse<br />
• Spielobjekt, Bild parametrisiert<br />
• Taucht zufällig <strong>in</strong>tial irgendwo<br />
auf<br />
• Bewegt sich bei<br />
Richtungsänderung an e<strong>in</strong>er<br />
Wand zufällig (1–3) anders<br />
schnell weiter<br />
• Kann sich selbst zeichnen<br />
Logos, die verwendet werden<br />
• hsrm.png<br />
1 class Logo(object):<br />
2 def __<strong>in</strong>it__(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.rand<strong>in</strong>t(0,breite-r.width)<br />
7 r.top=random.rand<strong>in</strong>t(0,hoehe-r.height)<br />
8 self.dir = [random.rand<strong>in</strong>t(1,3),<br />
9 random.rand<strong>in</strong>t(1,3)]<br />
10 def bewege(self):<br />
11 if self.rect.left < 0:<br />
12 self.dir[0] = random.rand<strong>in</strong>t(1, 3)<br />
13 elif self.rect.right > breite:<br />
14 self.dir[0] = -random.rand<strong>in</strong>t(1, 3)<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 ma<strong>in</strong>():<br />
2 screen=pygame.display.set_mode(groesse)<br />
3 clock=pygame.time.Clock()<br />
4 logos=[Logo(screen) for i <strong>in</strong> range(17)]<br />
5 while True:<br />
6 clock.tick(60)<br />
7 for event <strong>in</strong> 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 />
• hsrml.png<br />
• pygame.png<br />
15 if self.rect.top < 0:<br />
16 self.dir[1] = random.rand<strong>in</strong>t(1, 3)<br />
17 elif self.rect.bottom > hoehe:<br />
18 self.dir[1] = -random.rand<strong>in</strong>t(1, 3)<br />
1 def setpos(self, pos):<br />
2 self.rect.left = pos[0]<br />
3 self.rect.top = pos[1]<br />
15 screen.fill((50,130,40))<br />
16 for logo <strong>in</strong> logos:<br />
17 logo.bewege()<br />
18 pygame.display.flip()<br />
19 self.rect = self.rect.move(self.dir)<br />
20 self.screen.blit(self.bild, self.rect)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 265 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 266 / 326<br />
Programmieren <strong>in</strong> Python<br />
Bibliotheken<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
pygame – Mehr, Kollisionserkennung<br />
Reguläre Ausdrücke<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 />
Reguläre Ausdrücke<br />
2 logos = []<br />
3 def __<strong>in</strong>it__(self, ...):<br />
• “Matchen”, f<strong>in</strong>de passenden Str<strong>in</strong>g<br />
4 ...<br />
• Flexibles Matchen auf “Pattern” mit Sonderzeichen<br />
5 self.alt_bild=pygame.image.load("pygame.png")<br />
• Erweiterte reguläre Ausdrücke, nicht Wildcards<br />
6 Logo.logos.append(self)<br />
7 def bewege(self):<br />
• In Java, Python, . . . verfügbar, Kommandozeile mit egrep<br />
8 ...<br />
Reguläre Ausdrücke <strong>in</strong> Skriptsprachen<br />
9 bild = self.alt_bild<br />
• Spezielle Bibliotheken (Python, PHP, Java) oder Teil der Sprache (Perl, awk)<br />
10 if self._collides_with()<br />
11 else self.bild<br />
• Kompilation des Patterns, Ausführen auf C-basierter Eng<strong>in</strong>e<br />
12 self.screen.blit(bild, self.rect)<br />
E<strong>in</strong>satz<br />
13 def _collides_with(self):<br />
•<br />
14 return [logo for logo <strong>in</strong> Logo.logos<br />
Str<strong>in</strong>gverarbeitung, Extraktion, Suchen/Ersetzen<br />
15 if logo != self<br />
• Test auf syntaktische Korrektheit (Email-Adresse, Telefonnummer)<br />
16 if self.rect.colliderect(logo.rect)]<br />
17 def ma<strong>in</strong>():<br />
18 ...<br />
19 for logo <strong>in</strong> Logo.logos:<br />
20 ...<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 267 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 268 / 326
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Matchen mit e<strong>in</strong>fachen Patterns<br />
Auswahlbereiche für e<strong>in</strong> Zeichen<br />
Teil des Str<strong>in</strong>gs<br />
• E<strong>in</strong> Pattern beschreibt e<strong>in</strong>en Teil des<br />
zu durchsuchenden Str<strong>in</strong>gs<br />
Pattern – Zeichen matchen sich selbst<br />
• Zum Beispiel matcht das Pattern fahr<br />
den Str<strong>in</strong>g erfahren<br />
Groß- und Kle<strong>in</strong>schreibung wird<br />
unterschieden<br />
• Das Pattern Fahr macht nicht den<br />
Str<strong>in</strong>g erfahren<br />
Sonderzeichen haben spezielle<br />
Bedeutung<br />
• . ˆ$ * + ? { } [ ] \ | ( )<br />
<br />
<br />
fahr<br />
erfahren<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 269 / 326<br />
Auswahl mit []<br />
[abcde]<br />
[a-z]<br />
[a-zA-Z]<br />
[abc$ˆ]<br />
[ˆa-z]<br />
[ab\cd]<br />
E<strong>in</strong>zelnes Zeichen: Matcht entweder a, b, c, d oder e<br />
Bereich: Matcht jeden (e<strong>in</strong>en) Kle<strong>in</strong>buchstaben (ASCII)<br />
Bereich: Matcht Groß- und Kle<strong>in</strong>buchstaben<br />
Sonderzeichen nicht aktiv <strong>in</strong> Bereichen. Matcht a, b, c, $ oder ˆ<br />
ˆam Anfang negiert den Bereich. Matcht alles außer Kle<strong>in</strong>buchstaben<br />
\ hebt die besondere Bedeutung auf. Matcht a, b, \, c oder d<br />
Vordef<strong>in</strong>ierte 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-E<strong>in</strong>stellungen<br />
werden berücksichtigt<br />
• Unicode? wieder alles anders...<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 270 / 326<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> 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 />
Besondere Zeichen und Bedeutung<br />
. beliebiges Zeichen {m,n} Wiederholung, m<strong>in</strong>destens<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 [ Beg<strong>in</strong>n Auswahl aus Zeichen<br />
+ Wiederholung 1 oder mehrfach ] Ende Auswahl aus Zeichen<br />
( Beg<strong>in</strong>n e<strong>in</strong>er Gruppierung ˆ Anfang Str<strong>in</strong>g/Zeile<br />
) Ende e<strong>in</strong>er Gruppierung [ˆ Negation/Auswahl<br />
{ Beg<strong>in</strong>n explizit gezählte<br />
$ Ende Str<strong>in</strong>g/Zeile<br />
Wiederholung<br />
} Ende explizit gezählte<br />
Wiederholung<br />
| Oder-Auswahl von<br />
Gruppierungen<br />
Pa(pa){1,3}gei<br />
Papagei, Papapagei, Papapapagei und sonst nichts<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 271 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 272 / 326
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Gierige Ausführung<br />
Beispiele<br />
Von l<strong>in</strong>ks 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 />
B<strong>in</strong>ä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 />
E<strong>in</strong>faches Ausprobieren <strong>in</strong> der Shell (bash)<br />
So viel wie möglich<br />
• Bei dem ersten passenden<br />
Teilausdruck<br />
• So viel wie möglich Zeichen <strong>in</strong> den<br />
Match br<strong>in</strong>gen<br />
a[bc]+<br />
xadyaabbbcccd<br />
matcht abbbccc,<br />
nicht Teil davon<br />
• echo | egrep "" # matcht Teilstr<strong>in</strong>g<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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 273 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 274 / 326<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Reguläre Ausdrücke und Wildcards<br />
Reguläre Ausdrücke<br />
Matchen von Str<strong>in</strong>gs<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 />
Wildcards<br />
Matchen von Str<strong>in</strong>gs<br />
In Shell, DOS, grep<br />
Standard Wildcards<br />
Beispiel Unterschiede<br />
a* passt auf jeden Str<strong>in</strong>g der mit a<br />
beg<strong>in</strong>nt; * steht für beliebige<br />
Zeichenfolge<br />
a? passt auf leeres Wort oder a a? passt auf jeden zwei Zeichen<br />
langen Str<strong>in</strong>g, der mit a beg<strong>in</strong>nt<br />
. . .<br />
Weitere Probleme<br />
• Groß-/Kle<strong>in</strong>schreibung unterschieden?<br />
Literatur und Onl<strong>in</strong>e-Quellen für Reguläre Ausdrücke<br />
Reguläre Ausdrücke allgeme<strong>in</strong><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 <strong>in</strong> Python<br />
• http://docs.python.org/2.7/library/re.html<br />
• http://docs.python.org/dev/howto/regex.html<br />
• Das $-Zeichen als Beg<strong>in</strong>n e<strong>in</strong>er Variable<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 275 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 276 / 326
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
re-Modul – Reguläre Ausdrücke <strong>in</strong> Python<br />
Beispiel – Kompilieren und Matchen<br />
Reguläre Ausdrücke <strong>in</strong> Python<br />
• re-Modul<br />
Kompilieren<br />
• Modul-Funktion compile<br />
1 >>> import re<br />
2 >>> pattern = re.compile(r’[a-z]+’)<br />
• Matche, modifiziere, zerteile, ersetze,<br />
. . .<br />
• Kompilation des “Patterns”<br />
• Kompilieren e<strong>in</strong>es regulären<br />
Ausdrucks erzeugt Patternobjekt<br />
Matchen<br />
1 >>> match = pattern.match(’abcABC’)<br />
2 >>> match.group()<br />
3 ’abc’<br />
• Ausführen auf C-Eng<strong>in</strong>e<br />
Ausführlich dokumentiert – Lesen!<br />
E<strong>in</strong>faches Beispiel<br />
• Pattern kompilieren<br />
• Matchen<br />
• Ergebnis ausgeben<br />
• oder alles auf e<strong>in</strong>mal<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 />
• Methoden des Patternobjekts<br />
• Mit match Suche <strong>in</strong> e<strong>in</strong>em Str<strong>in</strong>g ab<br />
Anfang<br />
• Mit search Suche <strong>in</strong> e<strong>in</strong>em Str<strong>in</strong>g<br />
irgendwo<br />
• Ergebnis ist Matchobjekt wenn<br />
erfolgreich, sonst None<br />
• Aus Match-Objekt mit group den<br />
Match (Str<strong>in</strong>g) extrahieren<br />
4 >>> match = pattern.match(’ABCabcABC’)<br />
5 >>> match<br />
6 >>> pr<strong>in</strong>t match<br />
7 None<br />
8 >>> match.group()<br />
9 AttributeError: ’NoneType’ object has no attrib<br />
10 >>> match = pattern.search(’ABCabcABC’)<br />
11 >>> match.group()<br />
12 ’abc’<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 277 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 278 / 326<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Beispiel – Optionen und Kompakt<br />
Optionen<br />
• re.IGNORECASE ignorieren von<br />
Groß-/Kle<strong>in</strong>schreibung<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 <strong>in</strong> e<strong>in</strong>em Ausdruck möglich >>> re.search(’[a-z]+’,<br />
8 "ABCabcABC",<br />
9 re.IGNORECASE).group()<br />
10 ’ABCabcABC’<br />
Backslash-Zirkus<br />
Problem<br />
• Mit \ (Backslash) werden Sonderzeichen Ihres besonderen Status beraubt<br />
• Viele Backslashes <strong>in</strong> Python s<strong>in</strong>d e<strong>in</strong> Problem<br />
Lösung<br />
• Text \section matchen benötigt \\\\section als Pattern<br />
• E<strong>in</strong> \ um das Backslash im Python Str<strong>in</strong>g zu haben<br />
• Die beiden anderen um das zweite Backslash für den regulären Ausdruck zu haben<br />
• Benutze “raw” Str<strong>in</strong>gs <strong>in</strong> 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 >>> pr<strong>in</strong>t 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 279 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 280 / 326
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Programmieren <strong>in</strong> Python<br />
Reguläre Ausdrücke<br />
Gruppierungen<br />
Modifizieren von Str<strong>in</strong>gs<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 />
def<strong>in</strong>iert 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 dr<strong>in</strong>"<br />
18 >>> pat = r’([a-z]+ )\1’<br />
Zerteilen von Str<strong>in</strong>gs<br />
• re.split(, )<br />
• Gibt Liste von Str<strong>in</strong>gs zurück<br />
• Zerteilt bei jedem<br />
Match von <br />
Suchen und Ersetzen<br />
• re.sub(,,)<br />
• Gibt neuen Str<strong>in</strong>g zurück<br />
• Bei jedem Match von <br />
<strong>in</strong> wird <br />
stattdessen e<strong>in</strong>gesetzt<br />
1 >>> pat = r’\W+’<br />
2 >>> s = "Das ist e<strong>in</strong> netter kle<strong>in</strong>er Test"<br />
3 >>> re.split(pat, s)<br />
4 [’Das’,’ist’,’e<strong>in</strong>’,’netter’,’kle<strong>in</strong>er’,’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 />
19 >>> pr<strong>in</strong>t re.search(pat, s).group()<br />
20 doppelt doppelt<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 281 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 282 / 326<br />
Thread-Programmierung<br />
E<strong>in</strong>führung<br />
Thread-Programmierung<br />
E<strong>in</strong>führung<br />
Multitask<strong>in</strong>g<br />
Threads<br />
Multitask<strong>in</strong>g<br />
• Mehrere D<strong>in</strong>ge “gleichzeitig” tun<br />
• Erwartetes Verhalten auf Rechnern<br />
• Musik, Web (+ Animation), Download<br />
• E<strong>in</strong> “D<strong>in</strong>g” ist meist e<strong>in</strong> Prozess<br />
• Eigener Speicher<br />
• Eigener Ausführungsstrang/-faden<br />
Zeit<br />
P1<br />
P2<br />
P3<br />
P4<br />
Prozesse<br />
• Eigener Speicher, eigener Ausführungsfaden<br />
• Fehler <strong>in</strong> e<strong>in</strong>em 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 />
P1<br />
P2<br />
• Beispiel: P1, P2 und P3/4 parallel; P4 nach nach P3<br />
Threads<br />
Prozessoren/Kerne und Prozesse<br />
• Teilen sich Speicher, eigener Ausführungsfaden<br />
P1<br />
P2<br />
• Ausführung der Prozesse auf Prozessoren/Kernen<br />
• Multitask<strong>in</strong>g auch bei e<strong>in</strong>em Kern<br />
• Zeitscheiben unterteilen Prozessorzeit<br />
• Jeder Prozess erhält abwechselnd e<strong>in</strong>e (sehr sehr<br />
kle<strong>in</strong>e) Zeitscheibe<br />
• Bei vielen Kernen mehr (parallele Zeitscheiben)<br />
• Aus Benutzersicht alles quasi gleichzeitig<br />
Zeit<br />
P3<br />
P1 P2<br />
P4<br />
Zeitscheibe<br />
Prozessor<br />
• Threads <strong>in</strong>nerhalb e<strong>in</strong>es Prozesses<br />
• Leichtgewichtiges Umschalten der Zeitscheiben,<br />
weniger Aufwand je Kontextwechsel<br />
• Verteilung Zeitscheiben auf alle Threads aller<br />
Prozesse (bei Betriebssystemunterstützung)<br />
• Nebenläufigkeit als Programmiermodell<br />
Zeit<br />
T1 T2 T3<br />
T4<br />
T5<br />
T6<br />
T7<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 283 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 284 / 326
Thread-Programmierung<br />
Programmieren mit Nebenläufigkeit<br />
Thread-Programmierung<br />
E<strong>in</strong>führung<br />
• Mehrere Ausführungsstränge/-fäden quasi gleichzeitig bei<br />
geme<strong>in</strong>samen Daten/Ressourcen<br />
• Tausende von Threads möglich, leichtgewichtiger<br />
• Komplex und mächtig bei Verwendung<br />
Weit verbreitet <strong>in</strong> 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 <strong>in</strong> Java<br />
E<strong>in</strong>satzgebiete<br />
• Ke<strong>in</strong> Warten bei I/O-Operationen, Überbrücken Latenzen bei<br />
Netzwerkkommunikation; zum Beispiel bei UI ke<strong>in</strong> “E<strong>in</strong>frieren 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 multiprocess<strong>in</strong>g-Modul<br />
Thread-Programmierung Thread-Programmierung <strong>in</strong> Python<br />
Thread-Programmierung <strong>in</strong> Python<br />
Globale Daten<br />
1 import thread<strong>in</strong>g, sys<br />
Java-Style<br />
2 from primegen import primes<br />
• Thread-API modelliert nach Java<br />
3<br />
• thread<strong>in</strong>g-Modul, Thread-Klasse<br />
4 class IthPrime(thread<strong>in</strong>g.Thread):<br />
T1 T2 T3 5 def __<strong>in</strong>it__(self, i):<br />
T4<br />
• Methode run überschreiben<br />
Beispiel – die i.-te Primzahl<br />
• Primzahlgenerator prim gegeben<br />
• Klasse erbt von thread<strong>in</strong>g.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 s<strong>in</strong>d thread-lokale Variablen<br />
(auf dem Stack)<br />
6 thread<strong>in</strong>g.Thread.__<strong>in</strong>it__(self)<br />
7 self.i = i<br />
8 def run(self):<br />
9 p = primes()<br />
10 for _ <strong>in</strong> range(self.i):<br />
11 e = p.next()<br />
12 self.ith_prime = e<br />
13 pr<strong>in</strong>t "done %d, %d" % (self.i, e)<br />
14 def get_ith_prim():<br />
15 return self.ith_prime<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 285 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 286 / 326<br />
Thread-Programmierung<br />
Thread-Programmierung <strong>in</strong> Python<br />
Thread-Programmierung<br />
Thread-Programmierung <strong>in</strong> Python<br />
Wiederholung – Primzahlgenerator<br />
Generieren von Primzahlen<br />
• 2 und 3 s<strong>in</strong>d Primzahlen<br />
• Ab da <strong>in</strong> Zweier-Schritten, wenn<br />
teilerfrei<br />
primegen.py<br />
1 def _teiler(x):<br />
2 return [t for t <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 287 / 326<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 pr<strong>in</strong>t "compute <strong>in</strong> background"<br />
• Eventuell würde Haupt-Thread sich 9 t.jo<strong>in</strong>()<br />
beenden (ohne weitere Maßnahme) 10 s = "Die %d.te Primzahl ist %d"<br />
11 pr<strong>in</strong>t s % (i, t.ith_prime)<br />
• Methode jo<strong>in</strong> auf Thread-Instanz<br />
12 pr<strong>in</strong>t "ready"<br />
blockiert und wartet auf das Ende des<br />
Threads<br />
Zugriff auf Daten<br />
• Zuweisungen Python: atomar, sichtbar<br />
(nicht wie <strong>in</strong> Java)<br />
• Direkter Zugriff auf Attribute <strong>in</strong><br />
Ordnung<br />
1<br />
2 if __name__ == ’__ma<strong>in</strong>__’:<br />
3 i = 3<br />
4 if sys.argv[1:]:<br />
5 i = <strong>in</strong>t(sys.argv[1])<br />
$ python ith_prime.py 1000<br />
compute <strong>in</strong> background<br />
done 1000, 7919<br />
Die 1000.te Primzahl ist 7919<br />
ready<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 288 / 326
Thread-Programmierung<br />
Thread-Programmierung <strong>in</strong> Python<br />
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Mehrere Threads<br />
Threads – Kontrolle Ablauf<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 Str<strong>in</strong>gs (<strong>in</strong> richtiger<br />
Reihenfolge)<br />
Reihenfolge <strong>in</strong> den Threads<br />
• Nicht vorhersagbar<br />
• Reihenfolge der done Ausgabe<br />
variiert<br />
1 if __name__ == ’__ma<strong>in</strong>__’:<br />
2 i = <strong>in</strong>t(sys.argv[1])<br />
3 ts = [IthPrime(j)<br />
4 for j <strong>in</strong> range(i, i+3)]<br />
5 for t <strong>in</strong> ts:<br />
6 t.start()<br />
7 for t <strong>in</strong> ts:<br />
8 t.jo<strong>in</strong>()<br />
9 for t <strong>in</strong> ts:<br />
10 s = "Die %d.te Primzahl ist %d"<br />
11 pr<strong>in</strong>t 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 />
Unmöglich Thread von außen zu stoppen<br />
• Es kann ke<strong>in</strong>e 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 (<strong>in</strong> Python)<br />
• E<strong>in</strong> Thread liest, anderer schreibt<br />
• Bool immer komplett geändert<br />
• Aktuelle Werte <strong>in</strong> CPython immer<br />
gleich sichtbar (nicht <strong>in</strong> Java)<br />
1 from thread<strong>in</strong>g import Thread<br />
2 from time import sleep<br />
3<br />
4 class Incer(Thread):<br />
5 def __<strong>in</strong>it__(self):<br />
6 Thread.__<strong>in</strong>it__(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 pr<strong>in</strong>t "x", x<br />
14 def anhalten(self):<br />
15 self.weiter = False<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 289 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 290 / 326<br />
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Threads– Kontrolle Ablauf, Verwendung<br />
Threads – Ende erreicht?<br />
Beispiel Ausgabe<br />
• isAlive, läuft Thread?<br />
• jo<strong>in</strong> verwenden<br />
1 from <strong>in</strong>cer import Incer<br />
2 from time import sleep<br />
3<br />
4 <strong>in</strong>c = Incer()<br />
5 <strong>in</strong>c.start()<br />
6 sleep(3)<br />
7 <strong>in</strong>c.anhalten()<br />
8 pr<strong>in</strong>t "Lebt?", <strong>in</strong>c.isAlive()<br />
Niemals aktiv warten!<br />
• CPU-Zeit mit Nichtstun/Warten<br />
verschwendet, hohe Last<br />
• Nie, nie, nie tun<br />
Thread.jo<strong>in</strong> ist ok<br />
• Wartet, dass Thread beendet wird<br />
1 from <strong>in</strong>cer import Incer<br />
2 from time import sleep<br />
3<br />
4 <strong>in</strong>c = Incer()<br />
5 # Thread beg<strong>in</strong>nt zu laufen<br />
6 <strong>in</strong>c.start()<br />
7 while <strong>in</strong>c.isAlive(): # busy wait, boese<br />
8 pass<br />
9 <strong>in</strong>c.jo<strong>in</strong>()<br />
10 pr<strong>in</strong>t "Lebt?", <strong>in</strong>c.isAlive()<br />
• Aktuell laufender Thread hält,<br />
verschwendet aber ke<strong>in</strong>e<br />
Prozessorzeit<br />
9 # weiter nach Thread-Ende<br />
1 from <strong>in</strong>cer import Incer<br />
x 1<br />
Nachteil von Thread.jo<strong>in</strong><br />
2 from time import sleep<br />
x 2<br />
Lebt? True<br />
x 3<br />
Lebt? False<br />
• Aktueller Thread läuft nicht weiter<br />
(aber das ist Intention)<br />
• Falls # was s<strong>in</strong>nvolles lange dauert,<br />
dann wird nicht gleich reagiert sobald<br />
der Thread zu Ende ist<br />
3<br />
4 <strong>in</strong>c = Incer()<br />
5 <strong>in</strong>c.start()<br />
6 # was s<strong>in</strong>nvolles<br />
7 <strong>in</strong>c.jo<strong>in</strong>()<br />
8 # Ergebnis des Threads verwenden<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 291 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 292 / 326
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Thread-Programmierung<br />
Kontrolle Ablauf<br />
Aktion nach Ende Thread – Naja<br />
Aktion nach Ende Thread – Besser<br />
Ziel<br />
• Etwas nach Ende e<strong>in</strong>es 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 s<strong>in</strong>nvolles lange dauert<br />
• Ke<strong>in</strong>e sofortige Reaktion falls<br />
Berechnung zu Ende<br />
1000.te Primzahl ist 7919<br />
1 import thread<strong>in</strong>g, primegen<br />
2 class Langlaeufer(thread<strong>in</strong>g.Thread):<br />
3 def __<strong>in</strong>it__(self, iteprim):<br />
4 thread<strong>in</strong>g.Thread.__<strong>in</strong>it__(self)<br />
5 self.iteprim = iteprim<br />
6 def run(self):<br />
7 p = primegen.primes()<br />
8 for _ <strong>in</strong> 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__ == ’__ma<strong>in</strong>__’:<br />
14 ite = 1000<br />
15 t = Langlaeufer(ite)<br />
16 t.start()<br />
17 # was anderes s<strong>in</strong>nvolles<br />
18 t.jo<strong>in</strong>()<br />
19 tup = (ite, t.get_prim())<br />
20 pr<strong>in</strong>t "%d.te Primzahl ist %d" % tup<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 />
• Ma<strong>in</strong>-Thread wird nicht beansprucht<br />
• Durch Übergabe “Callback” bleibt<br />
Implementierung unabhängig<br />
1000.te Primzahl ist 7919<br />
1 import thread<strong>in</strong>g, primegen<br />
2 class Langlaeufer(thread<strong>in</strong>g.Thread):<br />
3 def __<strong>in</strong>it__(self, itep, ende=None):<br />
4 thread<strong>in</strong>g.Thread.__<strong>in</strong>it__(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 _ <strong>in</strong> range(self.iteprim):<br />
10 e = p.next()<br />
11 self.prim = e<br />
12 self.am_ende(self.prim)<br />
13 if __name__ == ’__ma<strong>in</strong>__’:<br />
14 ite = 1000<br />
15 def pr<strong>in</strong>t_prim(iteprim):<br />
16 tup = (ite, iteprim)<br />
17 pr<strong>in</strong>t "%d.te Primzahl ist %d" % tup<br />
18 t = Langlaeufer(ite, pr<strong>in</strong>t_prim)<br />
19 t.start()<br />
20 # was anderes s<strong>in</strong>nvolles<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 293 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 294 / 326<br />
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Reihenfolgeproblem<br />
Kritischer Wettlauf – Beispiel Incer<br />
Thread-Ausführung ist nicht-determ<strong>in</strong>istisch<br />
• Ke<strong>in</strong>e Aussage welcher Thread zuerst beendet wird möglich<br />
• Ke<strong>in</strong>e Aussage welcher Thread(Teil) vor/nach anderem Thread(Teil) ausgeführt<br />
• Ke<strong>in</strong>e Aussage wann welche Anweisung <strong>in</strong> e<strong>in</strong>em Thread unterbrochen wird<br />
Problem bei geme<strong>in</strong>sam geschriebenen (shared) Daten<br />
• Bei getrennt genutzten oder Nur-Lese-Daten ke<strong>in</strong> Problem<br />
• Wann immer möglich Thread-lokale Daten verwenden, idealerweise ke<strong>in</strong>e shared<br />
Daten oder nur lesbare Daten<br />
• Falls shared Daten nur lesbar s<strong>in</strong>d und bei geme<strong>in</strong>samer Verwaltung sicher <strong>in</strong>itialisiert<br />
s<strong>in</strong>d, ke<strong>in</strong>e Inkonsistenz möglich<br />
• Reihenfolge des Schreibens bei geme<strong>in</strong>samen 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 e<strong>in</strong> Ausführungsstrang <strong>in</strong> kritischer Sektion (Sperren)<br />
Globale Variable x<br />
• Initial 0<br />
• Durch zwei Threads um 1 erhöht<br />
Problem<br />
• x+=1 s<strong>in</strong>d drei unterbrechbare<br />
Anweisungen<br />
• Lese (read/r) x <strong>in</strong> y<br />
• Berechne y = y + 1<br />
• Schreibe (write/w) y <strong>in</strong> x<br />
• Lesen und Schreiben der gleichen<br />
Variable x, Race condition<br />
• y unkritisch, thread-lokal, zwei Mal y<br />
Kritischer Wettlauf<br />
• Quasi gleichzeitiges Ausführen <strong>in</strong><br />
kritischem Bereich<br />
y<br />
6<br />
7<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=w(y)<br />
Kritischer<br />
Bereich<br />
x<br />
0<br />
? 12 ?<br />
x<br />
6<br />
7<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=w(y)<br />
y<br />
6<br />
7<br />
7<br />
statt 8<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 295 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 296 / 326
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Thread-Programmierung<br />
Kritischer Wettlauf, Race Condition<br />
Unsynchronisierter Incer <strong>in</strong> 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 thread<strong>in</strong>g import Thread<br />
2 x=0<br />
3 class Incer(Thread):<br />
4 def __<strong>in</strong>it__(self, runs):<br />
5 Thread.__<strong>in</strong>it__(self)<br />
6 self.runs = runs<br />
7 def run(self):<br />
8 global x<br />
9 for _ <strong>in</strong> xrange(self.runs):<br />
10 x += 1<br />
11 if __name__ == ’__ma<strong>in</strong>__’:<br />
12 runs = 10**6<br />
13 <strong>in</strong>c1, <strong>in</strong>c2 = Incer(runs), Incer(runs)<br />
14 <strong>in</strong>c1.start()<br />
15 <strong>in</strong>c2.start()<br />
16 <strong>in</strong>c1.jo<strong>in</strong>()<br />
17 <strong>in</strong>c2.jo<strong>in</strong>()<br />
18 if x != 2*runs:<br />
19 pr<strong>in</strong>t "Oooops",x,"statt",2*runs<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 />
e<strong>in</strong> Thread sich <strong>in</strong> e<strong>in</strong>em kritischen Bereich bef<strong>in</strong>det<br />
Beispiele für kritischen Bereich<br />
• x += 1, Lesen/ Schreiben geme<strong>in</strong>samer 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 # Beg<strong>in</strong>n kritischer Bereich<br />
2 x += 1<br />
3 # Ende kritischer Bereich<br />
1 # Beg<strong>in</strong>n kritischer Bereich<br />
2 y = x<br />
3 y += 1<br />
4 x = y<br />
5 # Ende kritischer Bereich<br />
1 # Beg<strong>in</strong>n 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 297 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 298 / 326<br />
Thread-Programmierung<br />
Sperren<br />
Thread-Programmierung<br />
Sperren<br />
Synchronisation mit Sperren<br />
Sperren ist aufwendig<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.__<strong>in</strong>it__(self)<br />
self.runs = runs<br />
8 def run(self):<br />
anfragender Thread suspendiert<br />
9 global x<br />
(schlafen gelegt)<br />
10 for _ <strong>in</strong> 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 se<strong>in</strong>, sonst wird es schwierig<br />
zu durchschauen)<br />
13<br />
14<br />
sperre.release() # Ende sicher<br />
if __name__ == ’__ma<strong>in</strong>__’:<br />
15 runs = 10**6<br />
• Best-Practice: acquire/release-Block<br />
16 <strong>in</strong>c1, <strong>in</strong>c2 = Incer(runs), Incer(runs)<br />
umschließt kritischen Bereich, 11–13<br />
17 <strong>in</strong>c1.start(); <strong>in</strong>c2.start()<br />
gut, da alles gesichert ;-)<br />
1 from thread<strong>in</strong>g import Thread, Lock<br />
2 x = 0<br />
3 sperre = Lock() # Guard<br />
4 class Incer(Thread):<br />
5 def __<strong>in</strong>it__(self, runs):<br />
18 <strong>in</strong>c1.jo<strong>in</strong>(); <strong>in</strong>c2.jo<strong>in</strong>()<br />
19 if x == 2*runs:<br />
20 pr<strong>in</strong>t "gut, da alles gesichert ;-)"<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 299 / 326<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 />
<strong>in</strong>c1, <strong>in</strong>c2 = Incer(runs), Incer(runs)<br />
<strong>in</strong>c1.start(); <strong>in</strong>c2.start()<br />
7 <strong>in</strong>c1.jo<strong>in</strong>(); <strong>in</strong>c2.jo<strong>in</strong>()<br />
• Beispiel, hohe Wahrsche<strong>in</strong>lichkeit<br />
8 if __name__ == ’__ma<strong>in</strong>__’:<br />
blockierter Bereich (hohe “Contention”)<br />
9 runs = 10**7<br />
• (e<strong>in</strong>e 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 e<strong>in</strong>e geme<strong>in</strong>same Variable<br />
immer mit derselben Sperre (dem<br />
Guard/Wächter)<br />
• Sperren kritischer Bereich für<br />
Korrektheit notwendig<br />
1 from <strong>in</strong>cerunsync import Incer as UIncer<br />
2 from <strong>in</strong>cermitlock 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 pr<strong>in</strong>t "Unsynced: %6.2f s" % t<br />
14 start = now()<br />
15 runit(SIncer, runs)<br />
16 t = now()-start<br />
17 pr<strong>in</strong>t "Synced : %6.2f s" % t<br />
Unsynced: 1.67 s<br />
Synced : 14.97 s<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 300 / 326
Thread-Programmierung<br />
Sperren<br />
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 e<strong>in</strong> Zähler erhöht<br />
• Verwendung: Sichere Methode <strong>in</strong> sicherer Methode<br />
• Verhalten wie <strong>in</strong> Java<br />
1 from thread<strong>in</strong>g import RLock<br />
2 sperre = RLock()<br />
3 class C(object):<br />
4 def a(self):<br />
5 sperre.acquire()<br />
6 pr<strong>in</strong>t "methode a"<br />
7 self.b()<br />
8 sperre.release()<br />
9 def b(self):<br />
10 sperre.acquire()<br />
11 pr<strong>in</strong>t "methode b"<br />
12 sperre.release()<br />
13<br />
14 if __name__ == ’__ma<strong>in</strong>__’:<br />
15 c = C()<br />
16 c.a()<br />
methode a<br />
methode b<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 301 / 326<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 <strong>in</strong> sicherem Objekt<br />
• Eigene Klasse mit sicheren<br />
Zugriffsmethoden<br />
• synchronized <strong>in</strong> Java<br />
• Lokales Sperrobjekt <strong>in</strong> 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 thread<strong>in</strong>g import RLock<br />
2 class Counter(object):<br />
3 def __<strong>in</strong>it__(self):<br />
4 self.count = 0<br />
5 self._lock = RLock()<br />
6 def <strong>in</strong>c(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 e<strong>in</strong> Monitor<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 302 / 326<br />
Thread-Programmierung<br />
Sperren<br />
Thread-Programmierung<br />
Sperren<br />
Sichere Objekte, Monitor, Verwendung<br />
Das with-Statement<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 ke<strong>in</strong>e Sperren verwenden<br />
• Entwickler kann ke<strong>in</strong>e Sperren<br />
vergessen<br />
RLock teurer <strong>in</strong> Python,<br />
Beispiel 2,5 Mal langsamer<br />
gut, da alles gesichert ;-)<br />
1 from thread<strong>in</strong>g import Thread<br />
2 from counter import Counter<br />
3 class Incer(Thread):<br />
4 def __<strong>in</strong>it__(self, counter, runs):<br />
5 Thread.__<strong>in</strong>it__(self)<br />
6 self.counter = counter<br />
7 self.runs = runs<br />
8 def run(self):<br />
9 for _ <strong>in</strong> xrange(self.runs):<br />
10 self.counter.<strong>in</strong>c()<br />
11 if __name__ == ’__ma<strong>in</strong>__’:<br />
12 runs = 10**6<br />
13 counter = Counter()<br />
14 <strong>in</strong>c1 = Incer(counter, runs)<br />
15 <strong>in</strong>c2 = Incer(counter, runs)<br />
16 <strong>in</strong>c1.start(); <strong>in</strong>c2.start()<br />
17 <strong>in</strong>c1.jo<strong>in</strong>(); <strong>in</strong>c2.jo<strong>in</strong>()<br />
18 if 2*runs == counter.value():<br />
19 pr<strong>in</strong>t "gut, da alles gesichert ;-)"<br />
with-Statement, e<strong>in</strong> Block<br />
• Default-Operationen bei E<strong>in</strong>tritt<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 thread<strong>in</strong>g import Thread<br />
2 from counterwith import Counter<br />
3 from IncerCounter import Incer<br />
4 no_<strong>in</strong>cers, <strong>in</strong>cruns = 300, 1000<br />
5 counter = Counter()<br />
6 <strong>in</strong>cers = [Incer(counter, <strong>in</strong>cruns) for _ <strong>in</strong> range(no_<strong>in</strong>cers)]<br />
7 for <strong>in</strong>cer <strong>in</strong> <strong>in</strong>cers: <strong>in</strong>cer.start()<br />
8 for <strong>in</strong>cer <strong>in</strong> <strong>in</strong>cers: <strong>in</strong>cer.jo<strong>in</strong>() # barrier<br />
1 from thread<strong>in</strong>g import RLock<br />
2 class Counter(object):<br />
3 def __<strong>in</strong>it__(self):<br />
4 self.count = 0<br />
5 self._lock = RLock()<br />
6 def <strong>in</strong>c(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 pr<strong>in</strong>t "got", counter.value(), "expected", no_<strong>in</strong>cers*<strong>in</strong>cruns<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 303 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 304 / 326
Thread-Programmierung<br />
Sperren<br />
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Zwei sichere Objekte komb<strong>in</strong>iert nicht unbed<strong>in</strong>gt 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 />
stattf<strong>in</strong>det<br />
• Alte Sperren jetzt nutzlos, nur noch<br />
Aufwand<br />
47786 Oopps von 100000 Tests: 47%<br />
1 from thread<strong>in</strong>g 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 _ <strong>in</strong> range(10**5):<br />
7 c1.<strong>in</strong>c(); c2.<strong>in</strong>c()<br />
8 class Peeker(Thread):<br />
9 def run(self):<br />
10 tests, oops = 0, 0<br />
11 for _ <strong>in</strong> 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 pr<strong>in</strong>t s % (oops, tests, prozent)<br />
18 zc, p = ZweiCounter(), Peeker()<br />
19 zc.start(); p.start()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 305 / 326<br />
Gefahren bei der Thread-Programmierung<br />
Safety, Sicherheit<br />
• Vermeide Fehler, die durch Lese/Schreib-Zugriff verschiedener Threads auf<br />
geme<strong>in</strong>same Variable entstehen (Reihenfolge)<br />
• Ke<strong>in</strong> Problem, falls ke<strong>in</strong>e geme<strong>in</strong>samen Variablem oder Nur-Lese Variablen<br />
• Ansonsten E<strong>in</strong>satz von Sperren<br />
Liveness, Fortschritt<br />
• Irgend etwas s<strong>in</strong>nvolles wird irgendwann passieren<br />
• Beispiele: Deadlock (wie <strong>in</strong> 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 306 / 326<br />
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
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 />
• Ke<strong>in</strong> Fortschritt mehr, unendliches<br />
Warten<br />
• Verschiedene Szenarios möglich<br />
Zweimal sperren auf e<strong>in</strong>er Sperre<br />
10 with self._lock:<br />
• In e<strong>in</strong>em 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 thread<strong>in</strong>g import Thread, Lock<br />
2 class Deadlock(Thread):<br />
3 def __<strong>in</strong>it__(self):<br />
4 Thread.__<strong>in</strong>it__(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 pr<strong>in</strong>t "fertig"<br />
15 d = Deadlock()<br />
16 d.start()<br />
17 d.jo<strong>in</strong>()<br />
18 # haengt, nie fertig<br />
Deadlock – Verschränkte Sperren<br />
Verschränkt Sperren auf zwei Sperren<br />
• E<strong>in</strong> Thread macht erst l1, dann l2<br />
• E<strong>in</strong> 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 thread<strong>in</strong>g import Thread, Lock<br />
2 l1, l2 = Lock(), Lock()<br />
3 class Deadlock(Thread):<br />
4 def __<strong>in</strong>it__(self, doDo=True):<br />
5 Thread.__<strong>in</strong>it__(self)<br />
6 self.d = doDo<br />
7 def mach(self):<br />
8 with l1:<br />
9 with l2:<br />
10 pr<strong>in</strong>t "mach"<br />
11 def do(self):<br />
12 with l2:<br />
13 with l1:<br />
14 pr<strong>in</strong>t "do"<br />
15 def run(self):<br />
16 f = self.do if self.d else self.mach<br />
17 for _ <strong>in</strong> range(10**4): f()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 307 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 308 / 326
Thread-Programmierung<br />
Gefahren bei der Thread-Programmierung<br />
Thread-Programmierung<br />
Besonderheiten bei Threads <strong>in</strong> Python<br />
Deadlock – Verschränkte Sperren, Ausführung<br />
Besonderheiten bei Threads <strong>in</strong> Python<br />
Verwendung<br />
• Zwei Instanzen<br />
• E<strong>in</strong>e mit Sperrreihenfolge<br />
l1, dann l2<br />
• E<strong>in</strong>e mit Sperrreihenfolge<br />
l2, dann l1<br />
• Meist ke<strong>in</strong> 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.jo<strong>in</strong>()<br />
8 d2.jo<strong>in</strong>()<br />
9<br />
10 # passiert wahrsche<strong>in</strong>lich nie<br />
11 pr<strong>in</strong>t "Ganz Fertig"<br />
GIL <strong>in</strong> CPython-Implementierung (und PyPy)<br />
• Global Interpreter Lock (GIL)<br />
• Nur e<strong>in</strong> Python-Thread kann zu e<strong>in</strong>em Zeitpunkt auf Python-Strukturen zugreifen<br />
• Nur e<strong>in</strong> Python-Thread läuft zu jedem Zeitpunkt<br />
• Ke<strong>in</strong>e effektive Nutzung von Mehrkernsystemen möglich<br />
• Trotzdem s<strong>in</strong>nvolle Nutzung von Wartezeiten bei Langläufern<br />
• GIL wird bei Warten auf externe Ereignisse (IO) losgelassen<br />
• Thread-Schedul<strong>in</strong>g von Laufzeitumgebung<br />
• Alle 100 Bytecode-Anweisungen<br />
• sys.getcheck<strong>in</strong>terval, sys.setcheck<strong>in</strong>terval<br />
• Alternative ab Python 2.6: multithread<strong>in</strong>g<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: thread<strong>in</strong>g verwenden, Wissen für Java-Programmierung verwendbar<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 309 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 310 / 326<br />
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Producer/Consumer<br />
Producer<br />
Situation<br />
• E<strong>in</strong> Produzent erzeugt Werte<br />
• E<strong>in</strong> Konsument verwendet Werte<br />
• Beide können unabhängig vone<strong>in</strong>ander 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 <strong>in</strong> Warteschlange<br />
• Konsument holt Werte aus der Warteschlange<br />
• Warteschlange ist geme<strong>in</strong>sames 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 />
• E<strong>in</strong>fügen/Entfernen nur e<strong>in</strong>er gleichzeitig<br />
Produzent<br />
Konsument<br />
Warteschlange<br />
flexible<br />
Größe<br />
Aufgabe<br />
• Erzeuge Zahlen von 1 bis anz<br />
Klasse Producer<br />
• E<strong>in</strong> Thread<br />
Geme<strong>in</strong>same 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 e<strong>in</strong>fügen<br />
producer.py<br />
1 from thread<strong>in</strong>g import Thread<br />
2 import time, random<br />
3 class Producer(Thread):<br />
4 def __<strong>in</strong>it__(self, anz, queue, qlock):<br />
5 Thread.__<strong>in</strong>it__(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 <strong>in</strong> 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.<strong>in</strong>sert(0, i)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 311 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 312 / 326
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Consumer<br />
Aufgabe<br />
• Alle Elemente aus<br />
Warteschlange aufsummieren<br />
Klasse Consumer, e<strong>in</strong> Thread<br />
Geme<strong>in</strong>same 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 ke<strong>in</strong> Element <strong>in</strong> queue,<br />
e<strong>in</strong> bisschen warten<br />
consumer.py<br />
1 from thread<strong>in</strong>g import Thread<br />
2 import time, random<br />
3 class Consumer(Thread):<br />
4 def __<strong>in</strong>it__(self, queue, qlock):<br />
5 Thread.__<strong>in</strong>it__(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 />
Producer / Consumer<br />
1 from producer import Producer<br />
Geme<strong>in</strong>same Objekte anlegen<br />
2 from consumer import Consumer<br />
• Warteschlange, list<br />
3 from thread<strong>in</strong>g 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 jo<strong>in</strong><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 />
ke<strong>in</strong>e weiteren Werte kommen werden<br />
15 producer.jo<strong>in</strong>()<br />
• Auf Ende Consumer warten<br />
16 consumer.done = True<br />
Ergebnis ist fertig<br />
misses: 91<br />
17 consumer.jo<strong>in</strong>()<br />
18<br />
19 pr<strong>in</strong>t "misses:", consumer.misses<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 313 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 314 / 326<br />
Thread-Programmierung<br />
Producer/Consumer Pattern<br />
Thread-Programmierung<br />
wait/notify<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 f<strong>in</strong>det ke<strong>in</strong>en Wert<br />
• Warteschlange voll: Produzent generiert ke<strong>in</strong>en Wert<br />
• Aber <strong>in</strong> beiden Fällen wir Schleife durchlaufen<br />
• Rechenzeit wird verbraucht ohne Effekt<br />
(Teil-)Lösung bisher<br />
• Wenn Extremsituation e<strong>in</strong>tritt, dann e<strong>in</strong> 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 e<strong>in</strong>gefügt wird, dann soll Konsument geweckt werden<br />
• Spezielle Konstrukte für Schlafen/Aufwecken s<strong>in</strong>d wait/notify<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 315 / 326<br />
wait/notify<br />
Condition<br />
• Klasse von thread<strong>in</strong>g<br />
• Hält <strong>in</strong>tern Sperre, kann sie auch<br />
beim Initialisieren bekommen<br />
• Implementiert Lock-Interface,<br />
acquire, release<br />
• Weitere Methoden wait, notify, notifyAll<br />
wait()<br />
• Lässt Sperre los (Sperre muss belegt se<strong>in</strong>), legt aktuellen Thread schlafen<br />
• Weiterlaufen erst, wenn notify oder notifyAll auf Condition gerufen wurde<br />
notify()<br />
• Sperre muss belegt se<strong>in</strong><br />
• Informiert e<strong>in</strong>en 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 <strong>in</strong>formiert<br />
Jedes Java Objekt implementiert wait, notify, notifyAll<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 />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 316 / 326
Thread-Programmierung<br />
wait/notify<br />
Thread-Programmierung<br />
wait/notify<br />
Producer mit wait/notify<br />
Aufgabe<br />
• Produzent ohne aktives Warten<br />
Geme<strong>in</strong>same 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 <strong>in</strong> queue, dann ke<strong>in</strong>s<br />
mehr produzieren; de facto<br />
Warteschlange mit Länge 1<br />
• Falls e<strong>in</strong> Element dr<strong>in</strong> ist, dann wird<br />
e<strong>in</strong> 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 thread<strong>in</strong>g import Thread<br />
2 import time, random<br />
3 class Producer(Thread):<br />
4 def __<strong>in</strong>it__(self, queue, cond):<br />
5 Thread.__<strong>in</strong>it__(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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 317 / 326<br />
Consumer mit wait/notify<br />
Aufgabe<br />
• Schlafen legen, falls nichts<br />
verfügbar<br />
Geme<strong>in</strong>same 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 <strong>in</strong><br />
while-Schleife<br />
• Nach Aufwecken <strong>in</strong> gesperrtem<br />
Zustand<br />
consumeroaw.py<br />
1 from thread<strong>in</strong>g import Thread<br />
2 class Consumer(Thread):<br />
3 def __<strong>in</strong>it__(self, queue, cond, id):<br />
4 Thread.__<strong>in</strong>it__(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 pr<strong>in</strong>t msg<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 318 / 326<br />
Thread-Programmierung<br />
wait/notify<br />
Thread-Programmierung<br />
Spezielle Datentypen für Thread<strong>in</strong>g<br />
Producer/Consumer mit wait/notify<br />
Aufgabe<br />
• E<strong>in</strong> Produzent<br />
• Zwei Konsumenten, jeder liest<br />
• Ke<strong>in</strong>e 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 <strong>in</strong>sgesamt 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 thread<strong>in</strong>g 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.jo<strong>in</strong>(); c2.jo<strong>in</strong>()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 319 / 326<br />
Spezieller Warteschlangen-Datentyp<br />
Producer/Consumer<br />
• Typisches Pattern bei nebenläufigem Programmieren<br />
• Zentrale Datenstruktur ist Warteschlange<br />
• Umgeben von Synchronisations- und Warte-Idiomen<br />
Idee – spezielle Queue als vorgefertigter Datentyp<br />
• Sicheres Objekt<br />
• Sperre <strong>in</strong> Datentyp e<strong>in</strong>gebaut<br />
• Automatisches Sperren bei E<strong>in</strong>fügen, Holen und Löschen<br />
• Warte-Idiome <strong>in</strong>tegriert, automatisch schlafen legen<br />
• Blockierender Zugriff beim Holen, falls noch nichts da<br />
• Blockierender Zugriff beim E<strong>in</strong>fü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: E<strong>in</strong>facheres 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 320 / 326
Thread-Programmierung<br />
Spezielle Datentypen für Thread<strong>in</strong>g<br />
Thread-Programmierung<br />
Spezielle Datentypen für Thread<strong>in</strong>g<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 />
• In Java java.util.concurrent<br />
consumerqueue.py<br />
1 from thread<strong>in</strong>g import Thread<br />
2 from Queue import Empty<br />
3 class Consumer(Thread):<br />
4 def __<strong>in</strong>it__(self, queue, id):<br />
5 Thread.__<strong>in</strong>it__(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 pr<strong>in</strong>t msg % (self.id, summe)<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 321 / 326<br />
Consumer/Producer mit Queue<br />
producerqueue.py<br />
1 from thread<strong>in</strong>g import Thread<br />
2 class Producer(Thread):<br />
3 def __<strong>in</strong>it__(self, queue):<br />
4 Thread.__<strong>in</strong>it__(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 />
10 self.queue.put(i)<br />
11 i += 1<br />
done 2 15994664301<br />
done 1 14952448204<br />
• Es geht nichts verloren<br />
• Effizienter<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 />
14<br />
15 p.do = False<br />
16 c1.do, c2.do = False, False<br />
17<br />
18 c1.jo<strong>in</strong>(); c2.jo<strong>in</strong>()<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 322 / 326<br />
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Thread-Programmierung<br />
Worker-Thread Pattern<br />
Arbeits-Threads, Worker-Threads<br />
Worker Thread zum Addieren / 1<br />
Parallelisierung<br />
• Serialisierung, H<strong>in</strong>tere<strong>in</strong>anderausführung, e<strong>in</strong> Thread<br />
• Parallelisierung: E<strong>in</strong> 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 />
• E<strong>in</strong> 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 />
jetzt<br />
Worker<br />
Thread<br />
Thread-Verwaltung<br />
• Klassenvariable counter, e<strong>in</strong> 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 irgende<strong>in</strong> anderer Thread e<strong>in</strong>e<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 thread<strong>in</strong>g 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 __<strong>in</strong>it__(self, queue):<br />
10 Thread.__<strong>in</strong>it__(self)<br />
11 self.queue = queue<br />
12 self.id = Worker.count.<strong>in</strong>c()<br />
13<br />
14 def run(self):<br />
• Ohne Arbeit schlafen oder beenden<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 323 / 326<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 324 / 326
Thread-Programmierung<br />
Worker-Thread Pattern<br />
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 <strong>in</strong> 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 cont<strong>in</strong>ue<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 e<strong>in</strong> Element, noch e<strong>in</strong><br />
17 cont<strong>in</strong>ue<br />
Thread (id==1) und ke<strong>in</strong>e 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-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 325 / 326<br />
Worker Thread zum Addieren – Verwendung<br />
Verwendung<br />
• Zu addierende Zahlen <strong>in</strong> queue<br />
• Alle Worker starten, dann warten<br />
• Interessant ist eigentlich nur der mit<br />
id=1, da der sich als Letztes beendet<br />
Ke<strong>in</strong> gutes Beispiel<br />
• Aufwand je Task zu ger<strong>in</strong>g (Addition)<br />
• Wohl zu viele Threads für re<strong>in</strong>e<br />
Berechnung (ohne I/O)<br />
• Ke<strong>in</strong>e Nutzung von vielen Kernen mit<br />
CPython<br />
Besseres Beispiel nächstes Semester<br />
• Servlet Eng<strong>in</strong>e, 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 <strong>in</strong> xrange(1, bis+1):<br />
6 queue.put(ele)<br />
7 workers = []<br />
8 for _ <strong>in</strong> xrange(anzworker):<br />
9 workers.append(Worker(queue))<br />
10 for worker <strong>in</strong> workers:<br />
11 worker.start()<br />
12 for worker <strong>in</strong> workers:<br />
13 worker.jo<strong>in</strong>()<br />
14 summe = queue.get()<br />
15 pr<strong>in</strong>t "Summe ist %d" % summe<br />
16 summe = sum(range(1, bis+1))<br />
17 pr<strong>in</strong>t "Summe sollte se<strong>in</strong> %d" % summe<br />
Summe ist 5000050000<br />
Summe sollte se<strong>in</strong> 5000050000<br />
Prof. Dr. Peter Barth (HS-Rhe<strong>in</strong>Ma<strong>in</strong>) Programmieren 3 29. Januar 2013 326 / 326