07.11.2014 Aufrufe

Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain

Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain

Programmieren 3 Skript - Medieninformatik - Hochschule RheinMain

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

<strong>Programmieren</strong> 3<br />

<strong>Programmieren</strong> in C und Python<br />

Prof. Dr. Peter Barth<br />

<strong>Hochschule</strong> <strong>RheinMain</strong><br />

Fachbereich Design Informatik Medien<br />

<strong>Medieninformatik</strong><br />

29. Januar 2013<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 1 / 326


Organisatorisches<br />

Organisatorisches<br />

Vorlesung<br />

• Dienstags, 10:00 – 11:30 Uhr, Raum 11<br />

Praktikum<br />

• Duchmann: Di R13: C ab 8:15 Uhr, B ab 11:45 Uhr<br />

• Barth: Mo R13: E ab 16:00 Uhr, Di R15: A ab 11:45 Uhr,<br />

Mi R15: D ab 16:00 Uhr<br />

Vorlesungsfolien, Übungsblätter, weitere Informationen<br />

• Read.MI<br />

• http://www.mi.hs-rm.de/˜barth/hsrm/prog3<br />

Bewertung<br />

• Prüfungsleistung, Klausur 70 %<br />

• Studienleistung, Praktikum 30 %<br />

• Online-Test C<br />

• Online-Test Python<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 2 / 326


Organisatorisches<br />

Bewertung Praktikum<br />

Erreichbar<br />

• Online-Test C<br />

• Online-Test Python<br />

• Bonus beide Tests > 3 Punkte<br />

Bestanden<br />

• Mindestens 6 Punkte<br />

• Bis 9 Punkte ausreichend<br />

Keine Wiederholung der Online-Tests<br />

21 Punkte<br />

9 Punkte<br />

9 Punkte<br />

3 Punkte<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 3 / 326


Organisatorisches<br />

Ziele der Veranstaltung<br />

Weitere Sprachparadigmen und Sprachebenen verwenden<br />

• Umgang mit anderen Arten von Programmiersprachen<br />

• Auswahl Sprache und Paradigmen entsprechend der Aufgabe<br />

• Sprachparadigmen imperativ, funktional und logisch<br />

• Programmierparadigmen wie nebenläufiges <strong>Programmieren</strong>/Threading<br />

• Sprachebenen höhere Abstraktion und maschinennah<br />

• Einsatz und Nutzen passender Bibliotheken<br />

Umgang mit praxisrelevanten Sprachen in typischer Umgebung<br />

• Maschinennahes <strong>Programmieren</strong><br />

mit C<br />

• Höheres <strong>Programmieren</strong>/<strong>Skript</strong>en<br />

mit Python<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 4 / 326


Organisatorisches<br />

Maschinennahe Sprachen – C<br />

C, Ansi C<br />

• Maschinennahe Sprache<br />

• Systemnahe Programmierung<br />

• Erstellung von Bibliotheken<br />

• Eigene Speicherverwaltung<br />

• Spartanische,<br />

aber mächtige Entwicklungsumgebung<br />

Inhalt<br />

• Editor<br />

• Kommandozeilentools<br />

• Entwicklungsumgebung Kommandozeile<br />

• Datentypen, Kontrollstrukturen und Funktionen<br />

• Pointer und Speicherverwaltung<br />

• Zeichenkettenverarbeitung<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 5 / 326


Organisatorisches<br />

Ausdrucksstarke höhere Sprachen – Python<br />

Python<br />

• <strong>Skript</strong>sprache<br />

• Anwendungsentwicklung<br />

• Einfach Quellcode zu erstellen,<br />

zu lesen, zu warten<br />

• Interaktiv, viele IDEs<br />

• Integration verschiedener Sprachparadigmen,<br />

Einsatz nach Bedarf/Eleganz<br />

• Imperativ<br />

• Objekt-orientiert<br />

• Funktional<br />

• Einsatz von Bibliotheken: GUI, reguläre Ausdrücke, . . .<br />

Inhalt<br />

• Eingebaute mächtige Datentypen und Kontrollstrukturen<br />

• Funktionales <strong>Programmieren</strong> und Generatoren<br />

• Module und Klassen<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 6 / 326


Organisatorisches<br />

Thread-Programmierung<br />

Nebenläufiges <strong>Programmieren</strong> / Thread-Programmierung<br />

• Mehrere Ausführungsstränge gleichzeitig<br />

innerhalb eines Prozesses eines Anwendungsprogramms<br />

• Zeit sinnvoll nutzen während IO-Operationen<br />

• Nutzen von Mehrkernumgebungen<br />

Inhalt<br />

• Thread-API<br />

• Phänomene und Vermeidung<br />

• Typische Patterns<br />

Wissen 1:1 für Java-Umgebung nutzbar<br />

• In Python/Jython<br />

• Python Thread API wie Java Thread API<br />

Thread<br />

Objekt<br />

Sperre<br />

Objekt<br />

Thread<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 7 / 326


Organisatorisches<br />

Literatur<br />

C<br />

• C als erste Programmiersprache, Dausmann,<br />

Bröckl, Goll[Online verfügbar]<br />

• <strong>Programmieren</strong> in C, (ANSI C),<br />

Brian W. Kernighan, Dennis M. Ritchie<br />

• http://openbook.galileocomputing.de<br />

Python<br />

/c_von_a_bis_z/<br />

• http://www.python.org/doc<br />

• Einführung in Python, Mark Lutz und<br />

David Ascher, O’Reilly, 2. Auflage<br />

• Python Scripting for Computational Science,<br />

Langtangen, Springer<br />

Threading<br />

• Concurrent Programming in Java, Doug Lea<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 8 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Die Programmiersprache C<br />

Seit 1971 für Systemprogrammierung<br />

Ziel<br />

• Entwicklung/Portierung von Betriebssystem (Unix, PDP-7, DEC)<br />

• Statt Assembler, aber Performance vergleichbar mit Assembler<br />

• Hardware-nah, aber doch plattformunabhängig<br />

• Maschinennah, aber strukturierte Programmierung unterstützen<br />

Historie<br />

71: Ritchie, C (Weiterentwicklung von B, BCPL),<br />

Portierung von Unix (nur 10 % Assembler, Rest C)<br />

78: Kernighan & Ritchie, “The C Programming Language”<br />

89: Standardisierung, ANSI-C (Sprache, Bibliotheken),<br />

Überarbeitung C90, heute weit verbreitet<br />

99: C99, Einflüsse C++, noch nicht weit verbreitet<br />

Verwendung<br />

• Systementwicklung, „portabler Assembler“<br />

• Betriebssysteme (z.B. Unix, Linux), Tools (z.B. Shell, gtk)<br />

• Programmiersprachen (z.B. Java, Python, ...)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 9 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Verbreitung von C<br />

Weltweit ist C die meist verwendete Programmiersprache<br />

The C Programming Language<br />

• Klassisches Buch<br />

• Übersetzt in sehr viele Sprachen<br />

• http://cm.bell-labs.com/<br />

cm/cs/cbook/index.html<br />

Programming Language Index<br />

• Juli 2012 wieder die meist<br />

verwendete Sprache<br />

• http://www.tiobe.com/<br />

index.php/content/<br />

paperinfo/<br />

tpci/index.html<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 10 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Eigenschaften von C<br />

Imperativ, hardwarenah und plattformunabhängig<br />

C is declining somewhat in usage compared to C++, and maybe<br />

Java, but perhaps even more compared to higher-level scripting<br />

languages. It’s still fairly strong for the basic system-type things.<br />

Dennis Ritchie<br />

Imperative/Prozedurale Sprache<br />

• Typen, Variablen, Kontrollstrukturen, Funktionen<br />

• Zeiger und Bitoperationen in Sprache integriert, maschinennah<br />

• Kleiner Sprachkern, aber viele Operatoren<br />

• Keine Objektorientierung<br />

(C++ als C-Erweiterung mit OO-Konzepten)<br />

Getrennte Übersetzung<br />

• Übersetzung von Quelldateien in Objektdateien<br />

• Linken der Objektdateien zu ausführbarem Programm<br />

• Kein Modulkonzept, textueller Präprozessor<br />

Plattformunabhängig<br />

• Auf fast jeder Hardware verfügbar<br />

• Programme laufen auf jeder Hardware auf der C läuft,<br />

zumindest wenn man entsprechend programmiert<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 11 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Erstes Beispiel<br />

“Hello World” in C<br />

• Syntax ähnlich zu Java<br />

• Eigentlich umgekehrt<br />

1 Kommentare<br />

• Von /* und */ umschlossen<br />

• Nicht verschachtelt<br />

• Mehrere Zeilen möglich<br />

2 Makros<br />

• Kein Modulkonzept<br />

• Andere Dateien werden inkludiert,<br />

(Inhalt an die Stelle “kopieren”)<br />

• Makroanweisungen mit #...<br />

3 Whitespaces nicht relevant<br />

4 Funktionsdefinitionen<br />

• Eine Hauptfunktion je Programm<br />

• Name ist immer main<br />

1 /* the one and only */<br />

2 #include <br />

3<br />

4 int main(void) {<br />

5 printf("Hello C World\n");<br />

6 return 0;<br />

7 }<br />

5 Funktionsaufrufe<br />

• printf, in stdio.h deklariert<br />

• Mit einem Parameter<br />

6 Rückgabewert<br />

• Hauptfunktion gibt immer einen<br />

Integer-Wert zurück<br />

7 Ende der Funktion<br />

• Einrückregeln wie in Java erlaubt,<br />

andere möglich<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 12 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Übersetzen und Starten<br />

Separate Übersetzung in eine ausführbare Datei<br />

Datei hello.c mit Editor erstellen<br />

• Emacs oder vi empfohlen<br />

• Geany oder auch IDE möglich<br />

Übersetzen mit C-Compiler<br />

• (g)cc, (GNU) C Compiler<br />

• Erzeugt ausführbares Programm,<br />

Datei a.out<br />

Compiler-Optionen -g -ansi -Wall -o<br />

• Debug, ANSI-Standard, Warnung<br />

• Ausgabedatei ist hello<br />

Ausführen<br />

• Aufruf Name erzeugter Datei<br />

• Auf Kommandozeile<br />

• ./ davor wenn . nicht im Pfad<br />

$ ls -l hello.c<br />

-rwx------ 1 pb pb 80<br />

30. Aug 13:33 hello.c<br />

$ gcc hello.c<br />

$ ls -al a.out<br />

-rwx------ 1 pb pb 4699<br />

30. Aug 13:46 a.out<br />

$ ./a.out<br />

Hello C World<br />

$ gcc -g -ansi -Wall hello.c -o hello<br />

$ ls -l ./hello<br />

-rwx------ 1 pb pb 5871<br />

30. Aug 13:47 ./hello<br />

$ ./hello<br />

Hello C World<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 13 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Übersetzungsprozess<br />

Was passiert bei der Übersetzung im Detail<br />

Präprozessor<br />

• Fügt Quelltexte/Include-Dateien ein, Konvention<br />

Endung .h (Header), sucht Dateien in bestimmten<br />

Verzeichnissen /usr/include/...,<br />

• Textuelle Ersetzungen<br />

C-Compiler<br />

• Übersetzt C-Quellcode in hardwarespezifische<br />

Assemblersprache<br />

• Optimierungen<br />

Assembler<br />

• Übersetzt Assembler in Maschinensprache<br />

Linker<br />

• Bindet externen Objektcode ein (z.B. printf), sucht<br />

Bibliotheken in bestimmten Verzeichnissen<br />

/usr/lib/...,<br />

hello.c<br />

gcc hello.c -o hello<br />

Präprozessor<br />

C-Compiler<br />

Assembler<br />

Linker<br />

hello<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 14 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Makefiles<br />

Automatisierung des Übersetzungsprozesses ...<br />

Variablen<br />

1 Definition: CC=gcc<br />

• Verwendung mit $(CC)<br />

• Variablennamen per Konvention<br />

GROßBUCHSTABEN<br />

Regeln<br />

4 Ziel hello und Abhängigkeit hello.c<br />

• Um Ziel zu machen, schaue ob<br />

Abhängigkeit neuer ist als hello, wenn<br />

ja dann mache<br />

5 Führe Befehl (mit Ersetzungen) aus<br />

Verwenden auf Kommandozeile<br />

• Auf Kommandozeile make<br />

• Ziel als Parameter möglich<br />

Makefile<br />

1 CC=gcc<br />

2 CFLAGS=-ansi -g -Wall<br />

3<br />

4 hello: hello.c<br />

5 $(CC) $(CFLAGS) hello.c -o hello<br />

$ make<br />

gcc -ansi -Wall hello.c -o hello<br />

$ ./hello<br />

Hello C World<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 15 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Makefiles<br />

... etwas ausführlicheres Beispiel, Details im Informationsblatt<br />

Ziel all<br />

• Erstes Ziel ist Default-Ziel<br />

• Konvention all<br />

Trennen Compile/Link<br />

• Erst Objekt-Datei mit -c<br />

• Dann Binden/Linken<br />

Beispiel<br />

• Mache rot13 falls rot13.o neuer<br />

• Mache rot13.o falls rot13.c ...<br />

Ziel clean<br />

• Konvention, zum Löschen aller<br />

erzeugten Dateien<br />

• Ohne Abhängigkeit (Datei clean nicht<br />

vorhanden), immer ausführen<br />

Makefile<br />

1 CC=gcc<br />

2 CFLAGS=-ansi -g -Wall<br />

3<br />

4 all: hello rot13<br />

5<br />

6 hello: hello.c<br />

7 $(CC) $(CFLAGS) hello.c -o hello<br />

8<br />

9 rot13.o: rot13.c<br />

10 $(CC) -c $(CFLAGS) rot13.c -o rot13.o<br />

11<br />

12 rot13: rot13.o<br />

13 $(CC) $(CFLAGS) rot13.o -o rot13<br />

14<br />

15 clean:<br />

16 # - vor Befehl, ignoriere Fehlschlag<br />

17 -/bin/rm -f hello rot13 rot13.o<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 16 / 326


<strong>Programmieren</strong> in C<br />

Einführung in C<br />

Java versus C<br />

Objektorientiert<br />

Java<br />

Automatische Speicherverwaltung<br />

Ausnahmen<br />

Aussagekräftige Fehlermeldungen zu<br />

Laufzeit: Zum Beispiel IndexOutOf-<br />

Bounds, NullPointer<br />

Plattformunabhängige auf JVM ausführbare<br />

Dateien<br />

Getrennte Übersetzungseinheiten,<br />

klassenbasiert<br />

Namensräume<br />

String-Typ eingebaut<br />

C<br />

Prozedural, imperativ<br />

Manuelle Speicherverwaltung<br />

keine Ausnahmen, Konvention Fehler-<br />

Codes<br />

Keine Laufzeitfehlermeldungen: Abbruch<br />

durch Betriebssystem oder undefiniertes<br />

Verhalten<br />

Plattformabhängige<br />

Dateien<br />

Getrennte<br />

dateibasiert<br />

Keine Namensräume<br />

ausführbare<br />

Übersetzungseinheiten,<br />

Kein eingebauter String-Typ, Konvention<br />

char-Felder<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 17 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Variablen und Grundtypen<br />

Variablen und Grundtypen fast wie in Java<br />

Lokale Variablen<br />

• Deklaration (oder Vereinbarung) am<br />

Anfang der Funktion<br />

• Viele Compiler erlauben die<br />

Deklaration an beliebiger Stelle, wie in<br />

Java. Erst ab C99 erlaubt, vermeiden.<br />

• Erst Typname dann Variablenname<br />

4 Initialisierung möglich<br />

5 Mehrfachvereinbarung möglich<br />

Ausgabe mit printf<br />

• Konvention wie System.out.format<br />

1 #include <br />

2<br />

3 int main(void) {<br />

4 int i = 3;<br />

5 int j, k;<br />

6 double x = 3;<br />

7 j = 4;<br />

8 printf("%d\n", i+j);<br />

9 printf("%f\n", x*3.3);<br />

10 return 0;<br />

11 }<br />

• Dokumentation mit man 3 printf<br />

7<br />

9.900000<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 18 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Nicht initialisierte lokale Variablen<br />

Nicht initialisierte lokale Variablen haben undefinierten Wert<br />

Nicht initialisierte lokale Variablen<br />

• Deklarierbar und verwendbar<br />

• “Undefinierter” (beliebiger) Wert<br />

in der Variablen k<br />

Compiler/Laufzeit<br />

• Warnung nur bei höchster<br />

Warnstufe<br />

• Ausführung möglich<br />

• Undefiniertes Verhalten<br />

Variablen immer mit Wert initialisieren!<br />

1 #include <br />

2 int main(void) {<br />

3 int j, k;<br />

4 j = 4;<br />

5 printf("%d\n%d\n", j, j+k);<br />

6 return 0;<br />

7 }<br />

$ gcc -Wall ./nichtinit.c -o nichtinit<br />

./nichtinit.c: In Funktion "main":<br />

./nichtinit.c:9:9: Warnung: "k" wird in<br />

Funktion uninitialisiert verwendet<br />

$ ./nichtinit<br />

4<br />

134513308<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 19 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Globale und lokale Variablen<br />

Globale Variablen leben immer und werden initialisiert<br />

Globale/Externe Variablen<br />

• Außerhalb von Funktionen definiert<br />

• Können initialisiert werden<br />

• Wenn nicht explizit initialisiert, werden<br />

sie implizit mit 0 initialisiert<br />

• In allen Funktionen global verfügbar<br />

• In Java nicht vorhanden<br />

Lokale Variablen<br />

• Lebensdauer der Funktion nur<br />

innerhalb eines Blocks<br />

• Innere Variable gleichen Namens<br />

überdeckt äußere<br />

• Wie in Java<br />

• Ohne Initialisierung beliebiger Wert<br />

1 #include <br />

2 int i=3;<br />

3 int j,k;<br />

4 int main(void) {<br />

5 j = 4;<br />

6 printf("%d\n%d\n", j, j+k);<br />

7 { int lokal=3;<br />

8 printf("%d\n", lokal); }<br />

9 /* lokal nicht mehr vereinbart */<br />

10 return 0;<br />

11 }<br />

4<br />

4<br />

3<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 20 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Grundtypen – Ganze Zahlen<br />

Typen<br />

• char, short, int, long<br />

• Alternativen: short int statt short,<br />

long int statt long<br />

Vorzeichen<br />

• Vorsatz unsigned oder signed,<br />

Vorgabe ist signed<br />

• char kann auch unsigned sein,<br />

implementierungsabhängig<br />

Angabe von Werten<br />

• Zusatz mit U für unsigned und<br />

L für long<br />

• Automatisch konvertiert<br />

1 #include <br />

2 int main(void) {<br />

3 char c = 17;<br />

4 short s = 300;<br />

5 int i = 66666;<br />

6 long l = 66666L;<br />

7 return 0;<br />

8 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 21 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Grundtypen – Ganze Zahlen, Größen<br />

Größen-Hierarchie<br />

• char genau 1 Byte groß<br />

• char


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Rechnen mit Zahlen<br />

Ausdrücke<br />

• Operatoren, Präzedenzen, . . . ,<br />

wie von Java gewöhnt<br />

• Modulo-Arithmetik, Zweierkomplement<br />

Typkonversion<br />

• Automatische Konversion aller Werte zu<br />

mindestens int<br />

• Konvertiere danach erst zu Zieltyp<br />

Besonderheit Zuweisung<br />

• Zuweisung ist Ausdruck, Wert ist Wert der rechten<br />

Seite<br />

• = ist rechtsassoziativ<br />

c1 = c2 = 222 entspricht c1 = (c2 = 222)<br />

1 #include <br />

2 int main(void) {<br />

3 unsigned char c1, c2;<br />

4 short s;<br />

5 c1 = c2 = 222;<br />

6 s = c1 + c2;<br />

7 printf("%d\n", s);<br />

8 /* Ausgabe 444 */<br />

9 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 23 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Gleitkommazahlen<br />

Gleitkommanzahlen, Fließpunktzahlen<br />

• float und double als Datentypen wie<br />

in Java<br />

• zusätzlich long double<br />

• float


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Zeichen<br />

Datentyp char<br />

• Ganzzahliger Datentyp<br />

• Steht meist für ein Zeichen<br />

• Meist (trotzdem) signed,<br />

implementierungsabhängig<br />

• Genau ein Byte groß<br />

• Kleinster Datentyp in C<br />

Verwendung<br />

• Ganze Zahlen oder Zeichen<br />

• Zeichen sind ganze Zahlen<br />

• Entsprechung ’A’== 65 abhängig<br />

von Umgebung/Compiler<br />

1 #include <br />

2 int main(void) {<br />

3 char c0 = ’A’;<br />

4 char c1 = 65;<br />

5<br />

6 printf("%c, %c\n", c0, c1);<br />

7 printf("%d, %d\n", c0, c1);<br />

8 printf("%d\n", ’A’*’B’);<br />

9<br />

10 return 0;<br />

11 }<br />

A, A<br />

65, 65<br />

4290<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 25 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Kein Boolean, sondern ganze Zahlen<br />

Kein Boolean in C<br />

• ab C99 _Bool<br />

Ganze Zahlen als Boolescher Ausdruck<br />

• Jede ganze Zahl kann als Boolean<br />

interpretiert werden<br />

• Auch Ausdrücke möglich<br />

• 0 ist falsch,<br />

ungleich 0 ist wahr<br />

Boolesche Ausdrücke evaluieren zu<br />

Zahlen<br />

• Boolesche Ausdrücke (Operatoren)<br />

• Evaluieren zu<br />

0 (falsch) oder 1 (wahr)<br />

1 #include <br />

2 int main(void) {<br />

3 int zahl = 2;<br />

4 if (1)<br />

5 printf("ja1\n");<br />

6 if (zahl)<br />

7 printf("ja2\n");<br />

8 if (zahl-2)<br />

9 printf("ja3\n");<br />

10 printf("%d\n", zahl == 2);<br />

11 return 0;<br />

12 }<br />

ja1<br />

ja2<br />

1<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 26 / 326


<strong>Programmieren</strong> in C<br />

Variablen und Datentypen<br />

Aufzählungstypen<br />

Aufzählung mit enum<br />

• Definition von Konstanten<br />

• Kompatibel zu Typ int<br />

• Durch Komma getrennt<br />

• Optional mit Initialisierung<br />

• Dürfen überall auftauchen wo<br />

Konstanten erwartet werden<br />

(z.B. case in switch-Konstrukt)<br />

Initialisierung<br />

• Erste Konstante 0, wenn nicht<br />

initialisiert<br />

• Nächste Konstante immer um 1 höher,<br />

wenn nicht initialisiert<br />

Achtung: Nicht typsicher, kein<br />

Wertebereichs-Check<br />

1 #include <br />

2 enum skat { karo=9, herz, pik, kreuz };<br />

3 enum farbe { rot, gruen=17, blau };<br />

4<br />

5 int main(void) {<br />

6 enum skat blatt = karo;<br />

7 printf("karo=%d, herz=%d, "<br />

8 "pik=%d, kreuz=%d\n",<br />

9 karo, herz, pik, kreuz);<br />

10 printf("rot=%d, gruen=%d, blau=%d\n",<br />

11 rot, gruen, blau);<br />

12 blatt = 42; /* kein Check*/<br />

13 return 0;<br />

14 }<br />

karo=9, herz=10, pik=11, kreuz=12<br />

rot=0, gruen=17, blau=18<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 27 / 326


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Mengen mit Bitoperationen – Definition<br />

Beispiel für Aufzählungstypen<br />

Idee – Interpretiere Zahlen als Bitfeld<br />

• Shift-Operationen um mit 1


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Mengen mit Bitoperationen – Verwendung<br />

Beispiel für Aufzählungstypen<br />

Beispiel<br />

• Scheine von Rudi und Susi ausgeben<br />

• Susi und Rudi haben von den<br />

möglichen fünf Scheine<br />

• Von denen ist nur einer der Gleiche<br />

• Susi fehlen noch zwei Scheine<br />

Kein Wertebereichs-Check<br />

• Susi |= 0xFFFFFF<br />

• Wäre ok<br />

• Keine Überprüfung ob Wert einer der<br />

Werte des Aufzählungstyps ist<br />

1 int main(void) {<br />

2 enum Scheine Susi =<br />

3 Prog1 | Prog2 | Theo;<br />

4 int Rudi = Prog1 | Prog3 | ADS;<br />

5<br />

6 printschein(Susi);<br />

7 printschein(Rudi);<br />

8 printschein(Susi|Rudi);<br />

9 printschein(Susi&Rudi);<br />

10 printschein(~Susi);<br />

11 return 0;<br />

12 }<br />

Prog1 Prog2 Theo<br />

Prog1 Prog3 ADS<br />

Prog1 Prog2 Prog3 ADS Theo<br />

Prog1<br />

Prog3 ADS<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 29 / 326


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Variablen Definition und Deklaration<br />

Variablen Definition<br />

• Legt Typ fest<br />

• Reserviert Speicherplatz<br />

• Darf nur einmal vorkommen<br />

• Syntax wie gewohnt,<br />

global und lokal<br />

Variablen Deklaration<br />

• Legt Typ fest<br />

• Darf mehrmals vorkommen<br />

• Schlüsselwort extern davor,<br />

muss global sein<br />

Definition = Deklaration + Speicherplatz<br />

1 extern int exta; /* Deklaration */<br />

2 int main(void) {<br />

3 return exta;<br />

4 }<br />

5 /* Fehler, exta nicht definiert */<br />

1 extern int exta; /* Deklaration */<br />

2 extern int exta; /* Deklaration */<br />

3<br />

4 int exta = 3; /* Definition */<br />

5<br />

6 /* int exta = 3; Fehler Redefinition */<br />

7<br />

8 int main(void) {<br />

9 extern int exta; /* Deklaration */<br />

10 extern int exta; /* Deklaration */<br />

11 /* int exta; lokal nicht erlaubt */<br />

12 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 30 / 326


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Typ-Attribute – konstant<br />

Konstantenvereinbarung<br />

• Schlüsselwert const<br />

• Wert darf nicht verändert werden<br />

• Definition ohne Wert möglich (leider),<br />

Vorgabewert ist 0<br />

• extern möglich, muss dann später als<br />

const definiert werden<br />

Verwendung von const im Parametertyp<br />

• Wert darf dann in Funktion nicht<br />

verändert werden<br />

• Da Werte kopiert werden, sind<br />

Änderungen an z.B. einem int<br />

sowieso nur lokal<br />

#define nicht verwenden<br />

• Nicht typsicher, nicht Teil von C<br />

1 #define PI 3.14 /* boese */<br />

2<br />

3 const double pi = 3.14;<br />

4<br />

5 const int len=7+3;<br />

6<br />

7 extern const int c;<br />

8 const int c=3;<br />

9<br />

10 int f(void) {<br />

11 /* c = 4; Fehler */<br />

12 return c;<br />

13 }<br />

14<br />

15 int f2(const int i) {<br />

16 /* i = 4; Fehler */<br />

17 return i;<br />

18 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 31 / 326


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Typ-Attribute – const statt #define<br />

Präprozessor #define<br />

• Textersetzung, Text nach ersten<br />

Whitespaces durch Text nach zweiten<br />

Whitespaces<br />

• Keine Ersetzung in Zeichenketten und<br />

innerhalb von Bezeichnern<br />

• Alter Stil, als es const noch nicht gab<br />

• Nicht typsicher, tückisch, vermeiden<br />

Konstanten mit const<br />

• Definition einer Variablen mit<br />

konstantem Inhalt<br />

• Typsicher, Klar, verwenden<br />

enum für int-Konstanten<br />

• Wenn const nicht geht (z.B.<br />

Feldgrenzen), dann enum verwenden<br />

1 #include <br />

2<br />

3 #define PI 3.14<br />

4 const double pi = 3.14;<br />

5<br />

6 double umfangc(double radius) {<br />

7 return 2*pi*radius;<br />

8 }<br />

9 double umfangd(double radius) {<br />

10 return 2*PI*radius;<br />

11 }<br />

12<br />

13 #define LEN 7+3<br />

14 const int len=7+3;<br />

15<br />

16 int main(void) {<br />

17 printf("%3d\n", LEN*3); /* 16 */<br />

18 printf("%3d\n", len*3); /* 30 */<br />

19 return 0;<br />

20 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 32 / 326


<strong>Programmieren</strong> in C<br />

Bitoperationen<br />

Typ-Attribute – volatil<br />

Variable ändert sich “von außen”<br />

• Variable kann sich ohne Einwirkung<br />

des laufenden Programms ändern<br />

• Beispiel: Treiber für eine Hardware,<br />

die Ihren Zustand nicht auf Grund von<br />

Programmabläufen ändert<br />

• Gewünschtes Verhalten:<br />

• Compiler soll keine Optimierungen<br />

(Eliminiation aus Ausdrücken,<br />

Umordnung von Code) vornehmen<br />

• Wert muss jedesmal aus<br />

Speicherbereich gelesen werden<br />

volatil-Vereinbarung<br />

• Schlüsselwort volatile<br />

1 #include <br />

2<br />

3 int main(void) {<br />

4 volatile int x=3;<br />

5 int i, s=0;<br />

6 for (i=0; i < 1000; i+=1) {<br />

7 /* x wird immer hier neu gelesen */<br />

8 s += x*i;<br />

9 }<br />

10 return 0;<br />

11 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 33 / 326


<strong>Programmieren</strong> in C<br />

Eingabe und Ausgabe<br />

Ausgabe<br />

printf<br />

• Gibt 1. Parameter auf Standardausgabe aus<br />

Aufeinanderfolgende Strings werden zu einem<br />

zusammengefasst – vermeiden<br />

• Ersetzt alle %-Konstrukte in 1. Parameter durch<br />

jeweils nächsten Wert in den weiteren Parametern<br />

• Wie System.out.format, beliebig viele Parameter<br />

sprintf<br />

• Zusätzlicher 1. Parameter<br />

• In diesen String (1. Parameter) wird geschrieben statt<br />

Ausgabe nach stdout<br />

• Achtung: String muss lang genug sein<br />

putchar<br />

• Gibt Paramter (int nicht char) auf stdout aus<br />

• Erlaubt Ausgabe von Steuerzeichen (EOF, . . . )<br />

1 #include <br />

2 int main(void) {<br />

3 int d=42;<br />

4 char c=’a’;<br />

5 double g=3.14;<br />

6 printf(<br />

7 "int: %d\n"<br />

8 "char: %c\n"<br />

9 "double: %e\n",<br />

10 d, c, g);<br />

11 return 0;<br />

12 }<br />

int: 42<br />

char: a<br />

double: 3.140000e+00<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 34 / 326


<strong>Programmieren</strong> in C<br />

Eingabe und Ausgabe<br />

Eingabe<br />

scanf<br />

• Liest Zeichen von der Standardeingabe<br />

• Wie in 1. Parameter verlangt<br />

• Im Beispiel ist das Leerzeichen in der Eingabe wichtig<br />

• Bei %-Konstrukten wird entsprechender Wert erzeugt<br />

• Wert wird an die Adresse der Variablen (Notation mit<br />

&-Zeichen) gespeichert<br />

• Rückgabewert ist die Anzahl der erfolgreich<br />

eingelesenen Werte<br />

• Bei Fehlern geht es undefiniert weiter<br />

sscanf<br />

• Neuer erster Parameter, der Eingabestring<br />

• Eingabestring statt Lesen von stdin<br />

1 #include <br />

2<br />

3 int main(void) {<br />

4 int d;<br />

5 char c;<br />

6 double g;<br />

7 scanf("%d %c %lg",<br />

8 &d, &c, &g);<br />

9 printf("int: %d\n"<br />

10 "char: %c\n"<br />

11 "double:%e\n",<br />

12 d, c, g);<br />

13 return 0;<br />

14 }<br />

>> 42 a 3.14<br />


<strong>Programmieren</strong> in C<br />

Eingabe und Ausgabe<br />

Eingabe zeichenweise<br />

getchar<br />

• Ein Zeichen von stdin lesen<br />

• Wert ist Zeichen als int<br />

• Steuerzeichen möglich, zum Beispiel<br />

EOF am Ende einer Datei oder der<br />

Eingabe<br />

Beispiel: Eingabe auf Ausgabe kopieren<br />

• Zeichenweises einlesen von der<br />

Standardeingabe bis<br />

Dateiendezeichen (CTRL-D)<br />

• Zuweisung in Test, typisches Idiom<br />

1 #include <br />

2<br />

3 int main() {<br />

4 int c;<br />

5 while ((c = getchar()) != EOF) {<br />

6 putchar(c);<br />

7 }<br />

8 return 0;<br />

9 }<br />

• putchar als Gegenstück zu getchar<br />

• getc zur Angabe eines<br />

Eingabe-Stroms<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 36 / 326


<strong>Programmieren</strong> in C<br />

Eingabe und Ausgabe<br />

%-Konstrukte<br />

%-Konstrukte für ganze Zahlen<br />

• char: %c, int: %d, %i<br />

• unsigned int: %u dezimal, %o oktal,<br />

%x hexadezimal<br />

• long int: %ld, %li,<br />

short int: %hd, %hi<br />

%-Konstrukte Gleitkommenzahlen<br />

• float: %f(x.xx), %e(x.xxEyy), %g<br />

double: %lf(x.xx), %le(x.xxEyy), %lg<br />

• Modifier l nur bei Eingabe relevant,<br />

Ausgabe wird immer erst mindestens<br />

double<br />

Dokumentation<br />

• Mit man printf, man scanf<br />

• Gewöhnen Sie sich an man<br />

1 #include <br />

2 int main() {<br />

3 unsigned int d = 17;<br />

4 double f = 3.14;<br />

5<br />

6 printf("%%u: %u, %%o: %o, %%x: %x\n",<br />

7 d, d, d);<br />

8 printf("%%f: %f, %%e: %e, %%g: %g\n",<br />

9 f, f, f);<br />

10 f = 1.000000000000001;<br />

11 printf("%20.20f\n%20.20f\n",<br />

12 f, (float) f);<br />

13 return 0;<br />

14 }<br />

%u: 17, %o: 21, %x: 11<br />

%f: 3.140000, %e: 3.140000e+00, %g: 3.14<br />

1.00000000000000111022<br />

1.00000000000000000000<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 37 / 326


<strong>Programmieren</strong> in C<br />

Kontrollstrukturen<br />

Kontrollstrukturen wie in Java<br />

Bedingungen<br />

• Beliebige arithmetische Ausdrücke<br />

• Logische Operatoren geben 0 oder 1<br />

zurück<br />

Verzweigung<br />

• wie gewohnt<br />

• if, else, switch, break<br />

Schleifen<br />

• while, do while, break, continue<br />

• for<br />

anfang 0<br />

anfang 1<br />

anfang 0<br />

• Keine Variablenbelegung in for<br />

• Erlaubt ab C99<br />

1 #include <br />

2 int main(void) {<br />

3 int i;<br />

4 for (i=0; i < 3; i++) {<br />

5 int j=2, k=0;<br />

6 while (j)<br />

7 j--;<br />

8 j = 1


<strong>Programmieren</strong> in C<br />

Funktionen<br />

Funktionen<br />

Funktionsdefinition ähnlich zu Java<br />

• Auf oberster Ebene<br />

• Nicht geschachtelt<br />

Parameter<br />

• Parameter werden als Werte<br />

übergeben (call by value)<br />

• Keine Parameter mit (void)<br />

• Nur () veraltet, vermeiden<br />

• Beliebig viele Parameter mit (...)<br />

• prinf ist so definiert<br />

• Wird nicht weiter behandelt<br />

• Überladen ist nicht möglich<br />

Rückgabewert<br />

• Typ angeben (Vorgabe int, veraltet)<br />

• void für kein Rückgabewert<br />

1 #include <br />

2<br />

3 int f(void) {<br />

4 return 0;<br />

5 }<br />

6<br />

7 int inc(int i) {<br />

8 return i+1;<br />

9 }<br />

10<br />

11 int summiere(int i0, int i1) {<br />

12 return i0 + i1;<br />

13 }<br />

14<br />

15 int main(void) {<br />

16 int i = inc(3);<br />

17 return summiere(i, -i);<br />

18 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 39 / 326


<strong>Programmieren</strong> in C<br />

Funktionen<br />

Funktionsprototypen<br />

Problem – Benutzung vor Definition<br />

• Funktion wird verwendet, bevor sie definiert wurde<br />

• Andere Reihenfolge ist keine Lösung bei<br />

verschränkter Rekursion (odd, even)<br />

Lösung – Funktionsprototypen<br />

• Kopf der Funktion, Zeile 3<br />

• Ohne definierenden Block, mit Semikolon,<br />

Parameternamen dürfen fehlen<br />

• Funktion wird deklariert, noch nicht definiert<br />

• Angabe von extern davor erlaubt<br />

• extern int even(short int i);<br />

• Bekanntgabe des Rückgabewerts und des Typs des<br />

Parameters<br />

• Ohne Prototypen im Beispiel Übersetzungsfehler<br />

• Schlimmer wäre implizite Deklaration<br />

int even();<br />

1 #include <br />

2<br />

3 int even(short int i);<br />

4 int odd(short int i) {<br />

5 if (i == 0)<br />

6 return 0;<br />

7 return even(i-1);<br />

8 }<br />

9 int even(short int i) {<br />

10 if (i == 0)<br />

11 return 1;<br />

12 return odd(i-1);<br />

13 }<br />

14<br />

15 int main(void) {<br />

16 short int i = 17;<br />

17 printf("%d ist %s\n", i,<br />

18 odd(i) ? "odd" : "even");<br />

19 return 0;<br />

20 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 40 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Felder<br />

Feld<br />

• Speicherbereich mit mehreren gleich<br />

großen Elementen eines Typs<br />

• Zusammenhängender<br />

Speicherbereich<br />

Felder anlegen<br />

• Definition mit<br />

[]<br />

• Die Länge des Felds ist ein konstanter<br />

Ganzzahlausdruck, Angabe mit<br />

enum-Wert erlaubt<br />

• Ab C99 darf Länge eine Variable sein<br />

• In GCC erlaubt, nicht verwenden<br />

• Index von 0 bis -1<br />

Beispiel: 10 int Werte<br />

int a[10];<br />

0 1 2 3 4 5 6 7 8 9<br />

enum { G=10 };<br />

...<br />

int a[G];<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 41 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Feldgröße<br />

Größe des Felds<br />

• Anzahl der Elemente mal Größe je<br />

Element<br />

• Gesamtgröße außerhalb des Blocks<br />

der Definition nicht verfügbar<br />

Beispiel<br />

• im Gegensatz zu Java<br />

• 10 Mal ein int der Größe 4,<br />

also 40 Byte<br />

• Bei Funktion f mit Feld als Parameter<br />

ist die verfügbar Größe nur die Größe<br />

des Zeigers (später)<br />

1 #include <br />

2 void f(int a[10]) {<br />

3 printf("in f : %ld\n", sizeof a);<br />

4 }<br />

5 int main(void) {<br />

6 int a[10];<br />

7 printf("in main: %ld\n", sizeof a);<br />

8 f(a);<br />

9 return 0;<br />

10 }<br />

in main: 40<br />

in f : 4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 42 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Auf Feldelemente zugreifen<br />

Zugriff mit []<br />

• Erlaubt von Index 0 bis Länge-1<br />

• Verwendung auf linker und rechter<br />

Seite der Zuweisung (=)<br />

• Wie in Java<br />

Beispiel<br />

• Initialisierung des Felds mit<br />

Quadratzahlen<br />

• Berechnung der Summe der ersten<br />

G-1 Quadratzahlen in Funktion<br />

sum=285<br />

1 #include <br />

2 enum { G=10 };<br />

3 int dosum(int a[], int length) {<br />

4 int sum=0, i;<br />

5 for(i=0; i < length; i++) {<br />

6 sum += a[i];<br />

7 }<br />

8 return sum;<br />

9 }<br />

10 int main(void) {<br />

11 int a[G], i;<br />

12 for(i=0; i < G; i++) {<br />

13 a[i] = i*i;<br />

14 }<br />

15 printf("sum=%d\n", dosum(a, G));<br />

16 return 0;<br />

17 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 43 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Zugriff außerhalb der Feldgrenzen<br />

Feldgrenzen<br />

• Keine Überprüfung der Feldgrenzen<br />

• Zugriff zunächst erlaubt<br />

• Verhalten außerhalb der Feldgrenzen<br />

undefiniert<br />

• Nicht wie in Java,<br />

keine Laufzeitumgebung wie in Java<br />

Fehlerverhalten<br />

• Es geht meistens schief<br />

• Meistens, aber nicht immer<br />

• (viel schlimmer) Nicht immer sofort<br />

• Bei Ausführung Programmabbruch<br />

durch Betriebssystem möglich<br />

(Speicherzugriffsfehler)<br />

• Tools wie valgrind helfen<br />

1 int main(void) { /* felderbumm.c */<br />

2 int a[30];<br />

3 a[30000] = 0;<br />

4 }<br />

Speicherzugriffsfehler<br />

1 int main(void) { /* feldernbumm.c */<br />

2 int a[30];<br />

3 a[1000] = 0;<br />

4 }<br />

% valgrind ./feldernbumm<br />

== Memcheck, a memory error detector<br />

== Invalid write of size 4<br />

== at 0x4004BC: main (feldernbumm.c:3)<br />

== Address 0x7ff0012f0 is not stack’d,<br />

malloc’d or (recently) free’d<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 44 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Felder kopieren<br />

Feldname<br />

• Kann verwendet werden als Konstante<br />

mit Adresse des ersten Feldelements<br />

• Insbesondere als Funktionsparameter<br />

nicht Feld sondern Adresse des Felds<br />

• Ändern der Feldinhalte möglich<br />

Kopieren?<br />

• Durch Zuweisung nicht möglich<br />

• In Java Zuweisung der Referenz<br />

• Bei Feld als Parameter werden dann<br />

Adressen kopiert<br />

• Nicht unbedingt was man will<br />

Richtig kopieren<br />

• Feldweise, wie in Java<br />

• Genauso bei Vergleich, Ausgabe, etc.<br />

1 #include <br />

2<br />

3 int main(void) {<br />

4 int a[30], b[30], i;<br />

5 /* a = b; nicht erlaubt */<br />

6 if (a == b)<br />

7 printf("NIE\n");<br />

8 for (i=0; i < 30; i++) /* init */<br />

9 a[i] = 0;<br />

10 for (i=0; i < 30; i++) /* copy */<br />

11 b[i] = a[i];<br />

12 return 0;<br />

13 }<br />

14<br />

15 void f(int x[30], int y[30]) {<br />

16 x = y; /* erlaubt aber sinnlos */<br />

17 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 45 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Mehrdimensionale Felder<br />

Definieren mehrdimensionaler Felder<br />

• Definition durch Angabe weiterer<br />

Dimensionen<br />

• [3][5] nicht [3,5]<br />

• Größe entspricht Grundgröße mal<br />

Produkt der Dimensionen<br />

• Immer noch ein zusammenhängender<br />

Speicherbereich<br />

Struktur<br />

• Zeilenweise (row major)<br />

• Letzter Index läuft am schnellsten<br />

Beispiel<br />

• Feld a von 3 Zeilen mit je 5 Zahlen<br />

• Insgesamt (3 · 5) · 4 = 60 Byte<br />

1 int a[3][5], i, j;<br />

2 printf("%lu\n", sizeof a);<br />

3 for (i=0; i < 3; i++) {<br />

4 for (j=0; j < 5; j++)<br />

5 a[i][j] = i*5+j;<br />

6 }<br />

7 for (i=0; i < 3; i++) {<br />

8 for (j=0; j < 5; j++)<br />

9 printf("%2d ", a[i][j]);<br />

10 printf("\n");<br />

11 }<br />

0 1 2 3 4<br />

5 6 7 8 9<br />

10 11 12 13 14<br />

60<br />

0 1 2 3 4<br />

5 6 7 8 9<br />

10 11 12 13 14<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 46 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Mehrdimensionale Felder als Parameter<br />

Problem – Dimensionen notwendig<br />

• Dimensionen notwendig um Position in<br />

Speicherbereich zu bestimmen<br />

• Alle Dimensionen außer der Ersten<br />

Zwang Angabe Dimensionen<br />

• Alle Dimensionen außer der Ersten<br />

müssen angegeben werden<br />

• Wenn nicht, dann Fehler<br />

• Alle Dimensionen außer der Ersten<br />

müssen stimmen<br />

Beispiel<br />

• Wenn nicht, dann Warnung<br />

• g1 ist ok<br />

• g2 ist nicht ok<br />

• Bei a fehlt die zweite Dimension<br />

• Bei b fehlt die zweite Dimension<br />

10<br />

1 void g1(int a[][5], int b[3][5],<br />

2 int c[10][5]) {<br />

3 printf("%2d %2d %2d\n",<br />

4 a[1][0], b[1][0], c[1][0]);<br />

5 printf("%2ld %2ld %2ld\n",<br />

6 &a[2][0] - &a[0][0],<br />

7 &b[2][0] - &b[0][0],<br />

8 &c[2][0] - &c[0][0]);<br />

9 }<br />

11 /* Fehler<br />

12 void g2(int a[3][], int b[][]) {} */<br />

0 1 2 3 4<br />

5 6 7 8 9<br />

10 11 12 13 14 5 5 5<br />

10 10 10<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 47 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Initialisierung von Feldern<br />

Initialisierungswerte mit {}<br />

• Funktioniert für eindimensionale und<br />

mehrdimensionale Felder<br />

• Es wird zeilenweise weiter aufgefüllt<br />

• Warnung bei modernen Compilern<br />

• Falls Elemente fehlen, dann werden<br />

diese mit 0 initialisiert<br />

Größe<br />

• Falls Dimension fehlt, dann so viele<br />

wie benötigt<br />

• Nur erste Dimension darf fehlen, die<br />

wird dann berechnet anhand der<br />

Initialisierungswerte<br />

• Keine dynamischen Feldgrößen!<br />

1 int a1[3][5] = { {0,1,2,3,4},<br />

2 {5,6,7,8,9},<br />

3 {10,11,12,13,14} };<br />

4 int a2[][5] = { 0,1,2,3,4,<br />

5 5,6,7,8,9,<br />

6 10,11,12,13,14 };<br />

7 char a3[5] = {1,2,3};<br />

8 int a4[] = {1,2,3};<br />

9 gibaus(a1); /* Ausgabe als Block */<br />

10 gibaus(a2); /* Wie schon angegeben */<br />

11 printf("%2d %2d %2d %2d %2d \n",<br />

12 a3[0], a3[1], a3[2], a3[3], a3[4]);<br />

13 printf("%lu \n", sizeof a4);<br />

0 1 2 3 4<br />

5 6 7 8 9<br />

10 11 12 13 14<br />

...<br />

1 2 3 0 0<br />

12<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 48 / 326


<strong>Programmieren</strong> in C<br />

Felder<br />

Zeichenketten<br />

Kein Zeichenketten-Typ in C!<br />

• Kein dedizierter Typ<br />

• Es wird ein char-Feld verwendet<br />

• Konvention<br />

• Zeichenkette wird mit Zeichen ’\0’<br />

(der Wert 0) abgeschlossen<br />

Keine Operatoren auf Zeichenketten<br />

• Kein kopieren, vergleichen,<br />

konkatenieren, . . .<br />

Bibiliotheken<br />

• Operationen sind Teil der<br />

Standardbibliothek<br />

• string.h, man 3 string<br />

• Verwendung mit Funktionsaufrufen<br />

Beispiel Zeile 8, kein Platz, trotzdem<br />

1 char s1[6] = "Hallo";<br />

2 char s2[11] = "Hallo";<br />

3 char s3[] = "Hallo";<br />

4 char s4[] = {’H’, ’a’, ’l’,<br />

5 ’l’, ’o’, ’\0’ };<br />

6 printf("%s %s %s %s\n", s1, s2, s3, s4);<br />

7 strcat(s2,s1);<br />

8 strcat(s3,s1);<br />

9 printf("%s", s2);<br />

s1 H a l l o \0<br />

s2 H a l l o \0 \0 \0 \0 \0 \0<br />

H a l l o \0<br />

s3 H a l l o \0<br />

H a l l o \0<br />

s4 H a l l o \0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 49 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Getrennte Übersetzung<br />

Größere Softwareprojekte<br />

• Alles in einer Datei nicht mehr sinnvoll<br />

• Keine Modularisierung, keine Pakete<br />

• Was tun?<br />

a.h<br />

#include<br />

b.h<br />

Getrennte Übersetzung<br />

• Getrennte Quell-Dateien, .c<br />

• Header-Dateien,<br />

• .h, mit #include verwenden<br />

• Typinformation, Prototypen, extern<br />

• Separat übersetzen<br />

• -c, nur übersetzen, nicht binden<br />

• Erstellt Objekt-Dateien, .o<br />

• Binden (linken)<br />

• Alle notwendigen Objekt-Dateien,<br />

Abhängigkeiten auflösen<br />

• Ausführbares Programm erzeugen<br />

a.c m.c b.c<br />

$ gcc -c a.c -o a.o<br />

a.o m.o b.o<br />

$ gcc a.o b.o c.o -o m<br />

m<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 50 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Getrennte Übersetzung – Beispiel Fibonacci/1<br />

Separate Fibonacci-Berechnung<br />

• Zwei Methoden, einmal rekursiv<br />

(fibr), einmal iterativ (fibi)<br />

• Gleiche Signatur, von/nach<br />

unsigned int<br />

Separate Datei, fibs.c<br />

• Übersetzung mit -c erzeugt fibs.o<br />

gcc -c fibs.c -o fibs.o<br />

• Die Symbole fibr und fibi werden<br />

bereit gestellt<br />

fibs.o<br />

<<br />

> fibr, fibi<br />

fibs.c<br />

1 unsigned int fibr(unsigned int n) {<br />

2 if ((n == 0) || (n == 1))<br />

3 return n;<br />

4 return fibr(n-1) + fibr(n-2);<br />

5 }<br />

6<br />

7 unsigned int fibi(unsigned int n) {<br />

8 unsigned int f0, f1 = 1, f2 = 0;<br />

9 if ((n == 0) || (n == 1))<br />

10 return n;<br />

11 while (--n) {<br />

12 f0 = f1+f2;<br />

13 f2 = f1;<br />

14 f1 = f0;<br />

15 }<br />

16 return f0;<br />

17 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 51 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Getrennte Übersetzung – Beispiel Fibonacci/2<br />

Verwenden<br />

• Prototypen, damit Typ stimmt<br />

• Aufruf der Funktion<br />

Übersetzen, wie fibs.c<br />

• Die Symbole fibr, fibi und printf<br />

werden benötigt<br />

• Das Symbol main wird bereit gestellt<br />

Binden (linken)<br />

• Alle Objekt-Dateien werden<br />

zusammengeklebt<br />

• gcc fibs.o fib.o -o fib<br />

• main als Start benötigt<br />

• printf in Standardbibliothek<br />

Ausführen: fib(10) = 55 = 55<br />

fib.c<br />

1 #include <br />

2 unsigned int fibr(unsigned int);<br />

3 unsigned int fibi(unsigned int);<br />

4<br />

5 int main(void) {<br />

6 const unsigned int n = 10;<br />

7 printf("fib(%d) = %d = %d\n",<br />

8 n, fibr(n), fibi(n));<br />

9 return 0;<br />

10 }<br />

fib.o<br />

< fibr, fibi,<br />

printf<br />

> main<br />

fibs.o<br />

<<br />

> fibr, fibi<br />

fib<br />

< main<br />

> printf<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 52 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Header-Dateien<br />

Problem – Mehrfachangabe Prototypen<br />

an jedem Vorkommen in der Anwendung<br />

Lösung – Header-Dateien<br />

• Endung per Konvention mit .h<br />

• Auslagern der Prototypen und extern<br />

Deklaration der Variablen<br />

Verwendung<br />

• Einbinden mit #include<br />

• Bei “ im aktuellen Verzeichnis, bei <<br />

nur im Systemverzeichnis<br />

Vorteile<br />

• Mit -I Suchpfad anpassbar<br />

• Wiederverwendbare Module<br />

• Schneller, nur Teile neu übersetzen<br />

• Paralleles Arbeiten einfacher möglich<br />

fibs.h<br />

1 unsigned int fibr(unsigned int);<br />

2 unsigned int fibi(unsigned int);<br />

fib.c<br />

1 #include <br />

2 #include "fibs.h"<br />

3 int main(void) {<br />

4 const unsigned int n = 10;<br />

5 printf("fib(%d) = %d = %d\n",<br />

6 n, fibr(n), fibi(n));<br />

7 return 0;<br />

8 }<br />

fibs.c<br />

1 #include "fibs.h"<br />

2 unsigned int fibr(unsigned int n) {<br />

3 ...<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 53 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Mehrfachinklusion<br />

Mehrfachinklusion bei großen Projekten<br />

• Header-Dateien inkludieren andere,<br />

die wieder andere Header-Dateien<br />

inkludieren<br />

• Dabei kann es passieren, dass eine<br />

Header-Datei mehrfach inkludiert wird<br />

Probleme<br />

• Schlimmstenfalls führt dies zu Fehlern<br />

bei der Übersetzung<br />

• Problematische<br />

Mehrfachvereinbarung zum Beispiel<br />

bei enum<br />

• Endlos-Inklusion falls ursprüngliche<br />

Datei wieder inkludiert wird<br />

• Auf alle Fälle unnötig lange<br />

Übersetzungszeit<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 54 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Präprozessor<br />

Präprozessor<br />

• Inkludieren mit #include<br />

• Textersetzungen mit #define<br />

• Tests mit #ifdef, #ifndef, #else<br />

Umsetzung<br />

• Ausführen der Ersetzungen vor dem<br />

eigentlichen Übersetzen<br />

• Zwischenergebnis nach Ersetzung<br />

mit Option -E<br />

gcc -E prepro.c > prepro.txt<br />

Einsatzgebiet<br />

• Für Konstanten vermeiden<br />

• Für Include-Guards verwenden<br />

1 #include <br />

2 #define TOLLE "SUPER"<br />

3 #define OK 0<br />

4 int main(void) {<br />

5 printf("Hallo %s TOLLE Welt\n", TOLLE);<br />

6 #ifdef TOLLE<br />

7 printf("Es ist was definiert\n");<br />

8 #else<br />

9 printf("Nix is");<br />

10 #endif<br />

11 return OK;<br />

12 }<br />

# 1 "prepro.c"<br />

# [ ... > 800 Zeilen ...]<br />

int main(void) {<br />

printf("Hallo %s TOLLE Welt\n", "SUPER")<br />

printf("Es ist was definiert\n");<br />

return 0;<br />

}<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 55 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Include-Guards<br />

Ziel: Vermeide Mehrfach-Inklusion<br />

• Wenn eine Header-Datei schon<br />

einmal inkludiert wurde,<br />

• Dann inkludiere sie nicht mehr<br />

• Es kann nicht sinnvoll sein<br />

• Deklarationen reichen einmal<br />

Lösung: Include-Guard<br />

• Definiere eine Konstante<br />

• Konvention Dateiname groß, Sonderzeichen<br />

durch Unterstrich ersetzt<br />

• Prüfe ob Konstante nicht definert ist<br />

• Berücksichtige Inhalte nur, wenn diese<br />

Konstate nicht definiert ist<br />

• Effekt: Nur bei ersten Mal wird Inhalt<br />

berücksichtigt<br />

fibs.h<br />

1 #ifndef FIBS_H<br />

2 #define FIBS_H<br />

3<br />

4 unsigned int fibr(unsigned int);<br />

5 unsigned int fibi(unsigned int);<br />

6<br />

7 #endif<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 56 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Beispiel Mehrfachinklusion mit Include-Guards – Schalter/1<br />

zustaende.h<br />

1 #ifndef ZUSTAENDE_H<br />

2 #define ZUSTAENDE_H<br />

3 enum zustand {aus, an};<br />

4 extern enum zustand initial;<br />

5 #endif<br />

zustaende.c<br />

1 #include "zustaende.h"<br />

2 enum zustand initial = aus;<br />

reset.h<br />

1 #include "zustaende.h"<br />

2 enum zustand reset(void);<br />

wechsel.h<br />

1 #include "zustaende.h"<br />

2 enum zustand wechsel(<br />

3 enum zustand aktuell);<br />

reset.c<br />

1 #include "reset.h"<br />

2 static int zaehler=0;<br />

3 static int f(void);<br />

4 enum zustand reset(void) {<br />

5 zaehler += 1+f();<br />

6 return initial;<br />

7 }<br />

8 static int f(void) { return 0; }<br />

wechsel.c<br />

1 #include "wechsel.h"<br />

2 static int zaehler=0;<br />

3 static int f(void);<br />

4 enum zustand wechsel(<br />

5 enum zustand aktuell) {<br />

6 zaehler += 1+f();<br />

7 return (aktuell == an) ? aus : an;<br />

8 }<br />

9 static int f(void) { return 0; }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 57 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Beispiel Mehrfachinklusion mit Include-Guards – Schalter/2<br />

Aufbau<br />

• Wir modellieren einen Schalter<br />

• zustand.h wird von allen gebraucht<br />

• zustand.h wird von reset.h und<br />

wechsel.h inkludiert<br />

• Das Hauptprogramm schalter<br />

resetted und schaltet und inkludiert<br />

entsprechend<br />

Problem<br />

• Mehrfachinklusion in einer<br />

Übersetzungsheit von zustand.h<br />

• Übersetzungsfehler<br />

Mehrfachvereinbarung enum zustand<br />

Lösung: Inlcude-Guard verhindert<br />

Mehrfachinklusion<br />

schalter.c<br />

1 #include <br />

2 #include "reset.h"<br />

3 #include "wechsel.h"<br />

4<br />

5 int main(void) {<br />

6 enum zustand schalter;<br />

7 schalter = reset();<br />

8 printf("%u\n", schalter);<br />

9 schalter = wechsel(schalter);<br />

10 printf("%u\n", schalter);<br />

11 return 0;<br />

12 }<br />

Include-Guards<br />

In jeder Header-Datei immer verwenden.<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 58 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Beispiel Mehrfachdefinition<br />

Problem, Zeile 4<br />

• Definition in einer Header-Datei<br />

• Extrem böse!<br />

• Nie, nie, nie machen<br />

• Da hilft auch kein Include-Guard<br />

Fehlerauftreten<br />

• Sobald Header-Datei in zwei<br />

verschiedenen Übersetzungseinheiten<br />

verwendet wird<br />

• Zweimal Speicherplatz reserviert für<br />

das gleiche Symbol<br />

Doppelt definiertes Symbol<br />

Vermeiden<br />

• In Header-Datei nur deklarieren<br />

• nie definieren<br />

zustaende.h<br />

1 #ifndef ZUSTAENDE_H<br />

2 #define ZUSTAENDE_H<br />

3 enum zustand {aus, an};<br />

4 enum zustand initial=an;<br />

5 #endif<br />

reset.o<br />

< ..<br />

> initial<br />

schalter.o<br />

< ..<br />

> initial<br />

wechsel.o<br />

< ..<br />

> initial<br />

Mehrfach definiertes Symbol initial<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 59 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Namenskollision und static<br />

Namenskollision<br />

• Situation: In zwei Quelldateien (.c<br />

Übersetzungseinheiten) wird zufällig<br />

der gleiche globale Name verwendet<br />

• Effekt: Das Binden geht schief (doppelt<br />

definiertes Symbol), die Variable kann<br />

von überall manipuliert werden<br />

Lösung – static<br />

• static definierte Variable auf globaler<br />

Ebene ist nur lokal für die<br />

Übersetzungseinheit definiert<br />

• Variable ist nicht sichtbar in anderen<br />

Übersetzungseinheiten<br />

• Gleicher Name darf mehrfach<br />

vorkommen<br />

• Dito für static definierte Funktionen<br />

wechsel.c<br />

1 #include "wechsel.h"<br />

2 static int zaehler=0;<br />

3 static int f(void);<br />

4 enum zustand wechsel...<br />

5 static int f(void) { return 0; }<br />

reset.c<br />

1 #include "reset.h"<br />

2 static int zaehler=0;<br />

3 static int f(void);<br />

4 enum zustand reset...<br />

5 static int f(void) { return 0; }<br />

Im Beispiel ist Zaehlvariable zaehler und<br />

Funktion f jeweils nur für<br />

Übersetzungseinheit wechsel.c bzw.<br />

reset.c gültig.<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 60 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Komplettes Makefile für schalter /1<br />

1,2 Definition Compiler und Optionen<br />

3,4 Definition Programme und Quellen<br />

7 all per Konvention erstes Ziel, soll<br />

“alles” machen<br />

9 Es wird die Datei make.depend<br />

eingelesen und als Teil des Makefiles<br />

interpretiert<br />

1-15 : Wie wird schalter erstellt<br />

17 Die Datei make.depend wird nicht<br />

selbst erstellt, der Gnu-C Compiler<br />

kann das auf Basis der Quellen<br />

machen. Das erste Mal eine leere<br />

Datei erstellen ($ touch<br />

make.depend), damit es los geht.<br />

Ansonsten bei Strukturänderungen<br />

#include im Quellcode.<br />

1 CC=gcc<br />

2 CFLAGS= -Wall -g -ansi<br />

3 PROGS=schalter<br />

4 SRC=schalter.c reset.c wechsel.c \<br />

5 zustaende.c<br />

6<br />

7 all: $(PROGS)<br />

8<br />

10<br />

9 include make.depend<br />

11 schalter: schalter.o wechsel.o \<br />

12 reset.o zustaende.o<br />

13 $(CC) $(CFLAGS) schalter.o \<br />

14 wechsel.o reset.o zustaende.o \<br />

15 -o schalter<br />

16<br />

17 depend:<br />

18 $(CC) -MM $(SRC) > make.depend<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 61 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Komplettes Makefile für schalter /2<br />

Fortsetzung Makefile<br />

1,2 Ein beliebtes Ziel ist test zur<br />

Test-Automatisierung, ein anderes<br />

übliches Ziel wäre run<br />

4 clean ist keine Datei und muss daher<br />

immer “erstellt” werden<br />

6 clean räumt Projekt auf. Alle<br />

generierten Dateien werden gelöscht.<br />

9 Endungen von zu verarbeitenden<br />

Dateien sind .o, .c und .h<br />

11 Generische Regel: Um eine .o Datei<br />

aus einer .c Datei mit gleichem<br />

Namen zu machen . . .<br />

12 $< für erste Abhängigkeit (.c-Datei),<br />

$@ für Ziel (die .o-Datei)<br />

1 test: $(PROGS)<br />

2 ./schalter<br />

3<br />

4 .PHONY: clean<br />

5<br />

6 clean:<br />

7 -/bin/rm *.o $(PROGS)<br />

8<br />

10<br />

9 .SUFFIXES: .o .c .h<br />

11 %.o : %.c<br />

12 $(CC) -c $(CFLAGS) $< -o $@<br />

13 %.o : %.c %.h<br />

14 $(CC) -c $(CFLAGS) $< -o $@<br />

13 Wenn auch von .h Datei abhängig<br />

Weitere Abhängigkeiten nicht generisch,<br />

make.depend<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 62 / 326


<strong>Programmieren</strong> in C<br />

Getrennte Übersetzung<br />

Nutzen des Makefiles<br />

$ make -f clean<br />

/bin/rm *.o schalter<br />

$ make depend<br />

gcc -MM schalter.c reset.c wechsel.c zustaende.c > make.depend<br />

$ cat make.depend<br />

schalter.o: schalter.c reset.h zustaende.h wechsel.h<br />

reset.o: reset.c reset.h zustaende.h<br />

wechsel.o: wechsel.c wechsel.h zustaende.h<br />

zustaende.o: zustaende.c zustaende.h<br />

$ make<br />

gcc -c schalter.c -o schalter.o<br />

gcc -c wechsel.c -o wechsel.o<br />

gcc -c reset.c -o reset.o<br />

gcc -c zustaende.c -o zustaende.o<br />

gcc schalter.o wechsel.o \<br />

reset.o zustaende.o -o schalter<br />

$ make test<br />

./schalter<br />

0<br />

1 Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 63 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeiger<br />

Arbeitsspeicher<br />

• . . . ist in Speicherzellen eingeteilt<br />

• . . . ist Byte-weise adressierbar<br />

• . . . ist Wort-weise strukturiert<br />

0x0A0<br />

0x0A4<br />

42<br />

*ptr<br />

• Adressraum meist 2 32 oder 2 64 Bytes<br />

Zeiger<br />

0x100<br />

0x0A0<br />

&val<br />

• Speicherzelle, die Adresse einer<br />

anderen Speicherzelle beinhaltet<br />

• Typisiert, Anfangsadresse eines Werts<br />

Notation Zugriff<br />

• * ptr: Wert auf den der Zeiger ptr<br />

verweist, Inhaltsoperator *<br />

• &val: Adresse von Wert val,<br />

Adressoperator &<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 64 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeiger – Definition und Verwendung<br />

Notation Typ-Definition<br />

• *: Definiert einen Zeiger<br />

name auf <br />

• Beispiel: int *ptr;<br />

ptr ist Zeiger auf int<br />

Beispiel:<br />

• Variable val ist an Speicher mit<br />

Adresse (Hex) 0x0A0 abgelegt<br />

• Variable ptr ist an Speicher mit<br />

Adresse (Hex) 0x100 abgelegt<br />

• 32-Bit Wörter<br />

Ausgabe<br />

42 42 0x0A0 0x0A0<br />

0x100<br />

0x0A0<br />

0x0A4<br />

0x100<br />

1 int val = 42;<br />

2 int *ptr = &val;<br />

3<br />

42<br />

0x0A0<br />

4 printf("%d %d %p %p\n",<br />

5 val, *ptr,<br />

6 (void *) &val,<br />

7 (void *) ptr);<br />

*ptr<br />

8 printf("%p\n", (void *) &ptr);<br />

&val<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 65 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeigergröße<br />

Zeigergröße<br />

• Zeigergröße selbst durch Maschine<br />

festgelegt<br />

• Zeigergröße meist 4-Byte (32-Bit) oder<br />

8 Byte (64 Bit)<br />

• Zeigergröße unabhängig von<br />

Werte-Typ<br />

Beispiel<br />

0x0A0<br />

0x0A4<br />

0x100<br />

0x104<br />

0x108<br />

42<br />

'A' 'B'<br />

0x0A0<br />

0x0A4<br />

0x0A5<br />

• Ein int und zwei char<br />

• Auf 32-Bit Maschinen ist ein int 4 Byte<br />

groß und ein char 1 Byte<br />

• Zeiger sind auf 32-Bit Maschinen 4<br />

Byte groß, unabhängig vom Basis-Typ<br />

42 A B<br />

0x0A0 0x0A4 0x0A5<br />

0x100 0x104 0x108<br />

1 int a = 42; char b = ’A’, c = ’B’;<br />

2 int *ap = &a; char *bp = &b, *cp = &c;<br />

3<br />

4 printf("%d %c %c\n", a, b, c);<br />

5 printf("%p %p %p\n",<br />

6 (void *) &a, (void *) &b, (void *) &c);<br />

7 printf("%p %p %p\n",<br />

8 (void *) &ap,(void *) &bp, (void *) &cp);<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 66 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeiger auf Zeichen, Zeichenketten<br />

Zeiger auf Zeichen<br />

• Zeichen (Byte) ist kleinste<br />

adressierbare Einheit (Speicherzelle)<br />

Zeichenketten<br />

• Name des Felds kann als konstanter<br />

Zeiger auf das erste Element<br />

verwendet werden<br />

• Dereferenzierung entspricht<br />

Feldzugriff an Stelle 0<br />

• Achtung: Ein Zeichen ist ein<br />

Ganzzahltyp<br />

Beispielausgabe<br />

A 65 0x0A3<br />

B B 0x0A4 0x0A4<br />

0x0A0<br />

0x0A4<br />

0x100<br />

1 char ch = ’A’;<br />

'A'<br />

'B' 'C' 'D' '\0'<br />

0x0A3<br />

0x0A4<br />

2 char *chptr = &ch;<br />

3 char str[4] = "BCD";<br />

4 printf("%c %d %p\n",<br />

5 ch, ch, (void *) chptr);<br />

6 chptr = str;<br />

7 printf("%c %c %p %p\n",<br />

8 str[0], *chptr,<br />

9 (void *) chptr, (void *) &str[0]);<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 67 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeigerdefinition – Besonderheiten<br />

Syntax: *<br />

• Erst Typname <br />

• Dann Stern *<br />

• Schließlich Variablenname <br />

Beispiel: int *var<br />

Achtung<br />

• Der * bezieht sich auf den<br />

Variablennamen<br />

• Potentielles Problem bei mehreren<br />

Variablen in einer Definition<br />

• Der Typ eines Zeigers ist *<br />

Notationskonvention<br />

• * immer nahe am Variablennamen<br />

• Nie nahe am Typnamen<br />

1 int* ptr, qtr;<br />

1 /* entspricht */<br />

2 int *ptr;<br />

3 int qtr;<br />

1 int *ptr, *qtr;<br />

1 /* entspricht */<br />

2 int *ptr;<br />

3 int *qtr;<br />

int* ptr;<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 68 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Vorrangregeln von Operatoren<br />

Von hoch nach niedrig:<br />

10 () [] -> .<br />

Vorrang<br />

9 ! ˜ ++ -- + - * & (typ) sizeof<br />

8 * / %<br />

+ -<br />

7 ><br />

6 < >=<br />

== !=<br />

5 &<br />

ˆ<br />

|<br />

4 &&<br />

||<br />

3 ?:<br />

2 = += -= *= %= ˆ= &= =<br />

1 ,<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 69 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeiger – Beispiele/1<br />

1 unsigned long l0 = 0;<br />

2 unsigned long l1 = 1;<br />

3 unsigned long l2 = 2;<br />

4 unsigned long *pl[3] = {<br />

5 &l0, &l1, &l2 /* not ANSI-C, but C99 */<br />

6 };<br />

7 *pl[0] = 0;<br />

1 double d[3] = {1.0, 2.0, 3.0};<br />

2 double (*pd)[3] = &d;<br />

3 (*pd)[0] = 3.0;<br />

0 1 2<br />

pl 0x.. 0x.. 0x..<br />

l0 0 l1 1 l2 2<br />

0 1 2<br />

pd 0x.. d 1.0 2.0 3.0<br />

u 42<br />

1 unsigned int u=42;<br />

2 unsigned int *pu = &u;<br />

3 unsigned int **ppu = &pu;<br />

4 unsigned int ***pppu = &ppu;<br />

pppu<br />

ppu<br />

0x..<br />

pu<br />

0x..<br />

0x..<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 70 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeiger – Beispiele/2<br />

1 char ch;<br />

2 char *pc= &ch;<br />

3 char **ppc=&pc;<br />

4 char **xf[3][2];<br />

5 char **(*px)[3][2] = &xf;<br />

6<br />

7 ch = ’a’;<br />

8 *pc = ’a’;<br />

9 **ppc = ’a’;<br />

0 printf("%p %p\n",<br />

1 (void *) pc, (void *) ppc);<br />

2 xf[0][1] = ppc;<br />

3 **(*px)[0][1] = ’b’;<br />

4 printf("%c\n", ch);<br />

ppc<br />

px<br />

0x..<br />

0x..<br />

pc 0x.. ch<br />

xf 0<br />

1<br />

2<br />

0 1<br />

0x.. 0x..<br />

0x.. 0x..<br />

0x.. 0x..<br />

'a'<br />

'b'<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 71 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeigeroperationen, Zeiger auf void<br />

Operationen gleich(==), ungleich (!=)<br />

• Immer erlaubt<br />

• Test ob gleiche/ungleiche Adresse<br />

Zuweisung<br />

• Immer erlaubt<br />

• Gleicher Typ, sonst Warnung,<br />

vermeiden mit explizitem Cast<br />

• Von zu void * ohne Warnung<br />

void *, Zeiger auf beliebige Werte<br />

• Automatische Umwandlung bei<br />

Zuweisung<br />

• Dereferenzierung mit Inhaltsoperator<br />

verboten (was sollte rauskommen?)<br />

• Achtung: Böse, möglichst vermeiden<br />

1 char s[] = "hallo";<br />

2 char *cp = s;<br />

3 void *vp = cp;<br />

4 int *ip;<br />

5<br />

6 printf((s == cp) ? "==\n" : "!=\n");<br />

7 printf((s != cp) ? "!=\n" : "==\n");<br />

8<br />

9 ip = vp; /* keine Warnung */<br />

10 ip = cp; /* Warnung */<br />

11 ip = (int *) cp; /* keine Warnung */<br />

12<br />

13 printf("%i\n",<br />

14 *ip); /* was auch immer... */<br />

==<br />

==<br />

1819042152<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 72 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Zeigerarithmetik<br />

Zeiger und Zahlen<br />

• Addition und Subtraktion erlaubt<br />

• Ergebnis ist ein Zeiger<br />

• Effekt: Zeiger um Vielfaches des<br />

Platzbedarfs des Grundtyps ändern<br />

• typ *ptr; int i;<br />

int N = sizeof(typ);<br />

• ptr=ptr+i, ptr um i*N Byte erhöhen<br />

• ptr=ptr-i, um i*N Byte vermindern<br />

• ptr++, ptr--, ptr+=i . . . erlaubt<br />

Zeiger und Zeiger<br />

• Nur Subtraktion erlaubt<br />

• Ergebnis ist ganze Zahl<br />

Keine Zeigerarithmentik mit void *<br />

p p+1<br />

N Byte<br />

1 int ai[10];<br />

2 int *pi = &ai[0];<br />

3 double ad[10];<br />

4 double *pd = &ad[0];<br />

5 printf("%p %p %ld\n",<br />

6 (void *) pi, (void *) (pi+1),<br />

7 ((char *) (pi+1)) - ((char *) pi));<br />

8 printf("%p %p %ld\n",<br />

9 (void *) pd, (void *) (pd+1),<br />

10 ((char *) (pd+1)) - ((char *) pd));<br />

0x585e6210 0x585e6214 4<br />

0x585e61c0 0x585e61c8 8<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 73 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Beipiel – Zeichenketten<br />

Zeichenkette s mit Platz am Ende<br />

• Feld kann Zeiger zugewiesen werden<br />

Erste while-Schleife, Zeile 7<br />

• * ptr testet ob das Zeichen 0 ist<br />

• Läuft bis String-Ende<br />

Zweite while-Schleife, Zeile 9<br />

• Typische C-Idiom<br />

• Zuweisung, Zeigererhöhung und Test<br />

in einer Zeile<br />

• Doppelte Klammer vermeidet<br />

Warnung<br />

Gesamt<br />

• while-Schleifen – strcat(str, ttr)<br />

• for-Schleife – strlen(str)<br />

H a l l o u n d s o . \0<br />

1 char s[100] = "Hallo";<br />

2 char *p = s;<br />

3 char t[] = " und so.";<br />

4 char *q = t;<br />

5 int i;<br />

6<br />

7 while (*p)<br />

8 p++;<br />

9 while ((*p++ = *q++))<br />

10 ; /* leere Anweisung */<br />

11 p = s;<br />

12 for (i=0; *p++; i++)<br />

13 ; /* leere Anweisung */<br />

14 printf("%s (%d)\n", s, i);<br />

Hallo und so. (13)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 74 / 326


<strong>Programmieren</strong> in C<br />

Zeiger<br />

Rechnen mit Zeigern<br />

Zeigerarithmetik, gleicher Zeigertyp<br />

• Nur bei gleichen Zeigertypen sinnvoll<br />

• Beispiele<br />

cq - cp == 5<br />

cq == cp + 5<br />

cp == cq - 5<br />

Zeigerarithmetik bei verschiedenen<br />

Zeigertypen ist Unsinn<br />

• cq - ip ???<br />

• Keine Vermischung von Typen, was<br />

bedeutet +1?<br />

1 char cp[] = "abcdefghij";<br />

2 char *cq = cp+5;<br />

3 short int sp[] = {0,1,2,3,4};<br />

4 short int *sq = sp+2;<br />

5 int ip[] = {0, 1, 2};<br />

6 int *iq = ip + 1;<br />

7 double dp[] = { 3.1415, 2.7182 };<br />

8 double *dq = dp+1;<br />

cp<br />

cq<br />

a b c d e f g h i j<br />

sp<br />

sq<br />

0 1 2 3 4<br />

ip<br />

iq<br />

0<br />

1<br />

2<br />

dp<br />

dq<br />

3,1415<br />

2,<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 75 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeiger und Felder<br />

1 int af[] = {2,3,5,7,11,13,17,19,23,29};<br />

Feldnamen als Zeiger<br />

2 int i=6;<br />

• Der Name eines Feldes kann als<br />

3<br />

konstanter Zeiger auf das erste<br />

4 printf("%d == %d\n", af[i], *(af+i));<br />

Element des Feldes verwendet werden 5 printf("%d == %d\n", af[i], i[af]);<br />

Feldzugriff und Inhaltsoperation Zeiger<br />

• Es gilt ptr[i] == *((ptr) + (i))<br />

• Feldzugriff wird als Inhaltsoperation<br />

interpretiert<br />

• Äquivalenz gilt immer<br />

• Zeile 6: i[af] – so nicht<br />

programmieren<br />

Beispiel<br />

• Was macht nebenstehendes<br />

Programm?<br />

• 345 A 5<br />

17 == 17<br />

17 == 17<br />

1 char vstr[] = "12345";<br />

2 char *ptr = vstr;<br />

3<br />

4 printf ("%s %c %c", ptr+2,<br />

5 ’A’+ptr[5],<br />

6 3[ptr+1]);<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 76 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeiger und Felder sind nicht dasselbe/1<br />

Einem Feldnamen kann kein Zeiger<br />

zugewiesen werden<br />

• Der Feldname selbst ist kein Zeiger<br />

• Es wird kein Platz angelegt für den<br />

Feldnamen<br />

Ein Zeiger selbst braucht Speicherplatz<br />

• Der Zeiger beinhaltet die Adresse an<br />

der das erste Element des Feldes<br />

beginnt<br />

• Ein Zeiger zeigt bei Wertänderung auf<br />

andere Speicherbereiche<br />

1 char str[] = "abcde";<br />

2 char *ptr = "abcde";<br />

3<br />

4 ptr = str; /* geht */<br />

5 /* str = ptr; geht nicht */<br />

str a b c d e \0<br />

ptr 0x.. a b c d e \0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 77 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeiger und Felder sind nicht dasselbe/2<br />

Feld von Felder<br />

• Ein Feld von Feldern ist eigentlich ein<br />

grosses Feld<br />

• Row Major, zeilenweise<br />

• Die Größe ist fix<br />

1 char *pp[] =<br />

2 {"ein", "kleiner", "text"};<br />

3 char vv[][10] =<br />

4 {"ein", "kleiner", "text"};<br />

5 printf("%ld %ld\n", sizeof pp, sizeof vv)<br />

Feld von Zeiger<br />

12 30<br />

• Ein Feld von Zeigern ist ein normales<br />

eindimensionales Feld<br />

• Die Werte sind Zeiger auf Werte, bzw.<br />

Zeiger auf den Anfang von Feldern<br />

0<br />

1<br />

2<br />

pp<br />

0x..<br />

0x..<br />

0x..<br />

e i n \0<br />

k l e i<br />

t e s t<br />

n e r \0<br />

\0<br />

0<br />

1<br />

2<br />

vv<br />

e i n \0<br />

k l e i n e r \0<br />

t e s t \0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 78 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeigersalat<br />

1 char *c[] = { "ENTER", "NEW", "POINT",<br />

2 "FIRST" };<br />

3 char **cp[] = { c+3, c+2, c+1, c };<br />

4 char ***cpp = cp;<br />

5 printf("%s", **++cpp);<br />

6 printf("%s", *--*++cpp+3);<br />

7 printf("%s", *cpp[-2]+3);<br />

8 printf("%s\n", cpp[-1][-1]+1);<br />

0x..<br />

cpp<br />

3<br />

2<br />

0x..<br />

0x..<br />

0x..<br />

1<br />

0x..<br />

0<br />

cp<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

c<br />

F I R S<br />

P O I N<br />

N E W \0<br />

E N T E<br />

T \0<br />

T \0<br />

R \0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 79 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeigersalat – Zeile 5<br />

1 char *c[] = { "ENTER", "NEW", "POINT",<br />

2 "FIRST" };<br />

3 char **cp[] = { c+3, c+2, c+1, c };<br />

4 char ***cpp = cp;<br />

5 printf("%s", **++cpp);<br />

6 printf("%s", *--*++cpp+3);<br />

7 printf("%s", *cpp[-2]+3);<br />

8 printf("%s\n", cpp[-1][-1]+1);<br />

0x..<br />

cpp<br />

3<br />

2<br />

0x..<br />

0x..<br />

0x..<br />

1<br />

0x..<br />

0<br />

cp<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

c<br />

F I R S<br />

P O I N<br />

N E W \0<br />

E N T E<br />

T \0<br />

T \0<br />

R \0<br />

POINT<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 80 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeigersalat – Zeile 6<br />

1 char *c[] = { "ENTER", "NEW", "POINT",<br />

2 "FIRST" };<br />

3 char **cp[] = { c+3, c+2, c+1, c };<br />

4 char ***cpp = cp;<br />

5 printf("%s", **++cpp);<br />

6 printf("%s", *--*++cpp+3);<br />

7 printf("%s", *cpp[-2]+3);<br />

8 printf("%s\n", cpp[-1][-1]+1);<br />

0x..<br />

cpp<br />

3<br />

2<br />

0x..<br />

0x..<br />

0x..<br />

1<br />

0x..<br />

0<br />

cp<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

c<br />

F I R S<br />

P O I N<br />

N E W \0<br />

E N T E<br />

T \0<br />

T \0<br />

R \0<br />

POINTER<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 81 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeigersalat – Zeile 7<br />

1 char *c[] = { "ENTER", "NEW", "POINT",<br />

2 "FIRST" };<br />

3 char **cp[] = { c+3, c+2, c+1, c };<br />

4 char ***cpp = cp;<br />

5 printf("%s", **++cpp);<br />

6 printf("%s", *--*++cpp+3);<br />

7 printf("%s", *cpp[-2]+3);<br />

8 printf("%s\n", cpp[-1][-1]+1);<br />

0x..<br />

cpp<br />

3<br />

2<br />

0x..<br />

0x..<br />

0x..<br />

1<br />

0x..<br />

0<br />

cp<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

c<br />

F I R S<br />

P O I N<br />

N E W \0<br />

E N T E<br />

T \0<br />

T \0<br />

R \0<br />

POINTERST<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 82 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Zeigersalat – Zeile 8<br />

1 char *c[] = { "ENTER", "NEW", "POINT",<br />

2 "FIRST" };<br />

3 char **cp[] = { c+3, c+2, c+1, c };<br />

4 char ***cpp = cp;<br />

5 printf("%s", **++cpp);<br />

6 printf("%s", *--*++cpp+3);<br />

7 printf("%s", *cpp[-2]+3);<br />

8 printf("%s\n", cpp[-1][-1]+1);<br />

0x..<br />

cpp<br />

3<br />

2<br />

0x..<br />

0x..<br />

0x..<br />

1<br />

0x..<br />

0<br />

cp<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

c<br />

F I R S<br />

P O I N<br />

N E W \0<br />

E N T E<br />

T \0<br />

T \0<br />

R \0<br />

POINTERSTEW<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 83 / 326


<strong>Programmieren</strong> in C<br />

Zeiger und Felder<br />

Kommandozeilenparameter<br />

Parameter von main<br />

• Anzahl der Argumente (inklusive<br />

Name des Programms)<br />

int argc<br />

• Argumente als Feld von char-Zeigern<br />

char *argv[]<br />

Ähnlich wie in Java<br />

• Eigentlich umgekehrt<br />

args.c<br />

1 #include <br />

2<br />

3 int main(int argc, char *argv[]) {<br />

4 int i;<br />

5 for (i=0; i < argc; i++) {<br />

6 printf("%2d: %s\n", i, argv[i]);<br />

7 }<br />

8 return 0;<br />

9 }<br />

$ gcc args.c -o args<br />

$ args hallo tolle C Welt<br />

0: args<br />

1: hallo<br />

2: tolle<br />

3: C<br />

4: Welt<br />

0<br />

1<br />

2<br />

3<br />

4<br />

argv<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

0x..<br />

a r g s \0<br />

h a l l<br />

t o I l<br />

C \0<br />

W e l t \0<br />

o \0<br />

e \0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 84 / 326


<strong>Programmieren</strong> in C<br />

Funktionsparameter<br />

Funktionsparameter<br />

Grundtypen<br />

• In Java Werte<br />

Änderbare Parameter durch<br />

Verpacken in Objekte<br />

• In C Werte<br />

Änderbare Parameter durch<br />

Adressoperator (“call by reference”)<br />

• Idiom für z.B. scanf<br />

Felder<br />

• In Java als Referenz übergeben<br />

Werte in Feld ändern möglich<br />

Zuweisung heißt Referenz kopieren<br />

• In C Parameter als Zeiger übergeben<br />

Werte in Feld können geändert<br />

werden<br />

Zuweisung an Feld nicht möglich<br />

1 void f1(int *pi) { *pi = 17; }<br />

2 void g1(int a[]) {<br />

3 int c[3] = {1,2,3};<br />

4 a = c; /* erlaubt */ }<br />

5 void g2(int *a) {<br />

6 int c[3] = {1,2,3}; a = c; }<br />

7 void g3(int *a) { a[0] = 17; }<br />

1 int i=2;<br />

2 int a[3] = {2,3,5};<br />

3 int b[3] = {2,3,5};<br />

4 /* b = a; nicht erlaubt */<br />

5 f1(&i);<br />

6 /* i == 17 */<br />

7 g3(a);<br />

8 /* a[0] == 17 */<br />

9 scanf("%d", &i);<br />

10 /* i == */<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 85 / 326


<strong>Programmieren</strong> in C<br />

Strukturen<br />

Strukturen – struct<br />

Wie Java-Klasse ohne Methoden<br />

• Alle Komponenten public<br />

Definition mit struct<br />

• Variablendefinition bei<br />

struct-Deklaration möglich<br />

• Spätere Variablendefinition möglich,<br />

immer mit Schlüsselwort struct<br />

• Initialisierung in Reihenfolge der<br />

Deklaration möglich<br />

• Größe implementierungsabhängig<br />

Zugriff auf Komponenten mit .-Operator<br />

Zuweisung ist Kopie<br />

44<br />

• NICHT wie in Java<br />

1234 Susi Sinnlos<br />

4711 Willi Wahnsinn<br />

1 struct person {<br />

2 char name[40];<br />

3 unsigned int id;<br />

4 } susi;<br />

5<br />

6 struct person rudi;<br />

7 struct person willi = {<br />

8 "Willi Wahnsinn",<br />

9 4711<br />

10 };<br />

1 strcpy (susi.name, "Susi Sinnlos");<br />

2 susi.id = 1234;<br />

3 rudi = willi;<br />

4 willi.id = 123456;<br />

5 willi.name[0] = ’X’;<br />

6 printf("%6d %s\n", susi.id, susi.name);<br />

7 printf("%6d %s\n", rudi.id, rudi.name);<br />

8 printf("%ld\n", sizeof (struct person));<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 86 / 326


<strong>Programmieren</strong> in C<br />

Strukturen<br />

Strukturen – Speicherlayout<br />

Speicherlayout<br />

• Compiler entscheidet<br />

• Keine Annahmen treffen<br />

Beispiel<br />

• Findet heraus wo was liegt<br />

• Code nicht gut/portabel<br />

0<br />

4<br />

8<br />

12<br />

16<br />

a 0x44ac2d20<br />

b<br />

c d<br />

d<br />

e<br />

Füll-Bytes<br />

1 struct p1 {<br />

2 short a;<br />

3 int b;<br />

4 char c[3];<br />

5 char d[4];<br />

6 int e;<br />

7 };<br />

1 struct p1 p;<br />

2 char *base = (char *) &p;<br />

3 printf("== p:%p ==\n", base);<br />

4 printf("a:%2ld b:%2ld c:%2ld d:%2ld e:%2l<br />

5 ((char *) &p.a)-base, ((char *) &p.b)-ba<br />

6 ((char *) &p.c)-base, ((char *) &p.d)-ba<br />

7 ((char *) &p.e)-base);<br />

== p:0x44ac2d20 ==<br />

a: 0 b: 4 c: 8 d:11 e:16<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 87 / 326


<strong>Programmieren</strong> in C<br />

Strukturen<br />

Strukturen und Zeiger<br />

Zugriff mit -><br />

• pp->id ist Kurzform für (*pp).id<br />

• Erlaubt einfachen Zugriff auf<br />

Komponenten einer Struktur<br />

• Beispiel: 987654 Rudi Ratlos<br />

Bequem bei Zeigerketten<br />

• Beispiel: 0<br />

lp a b c<br />

0x.. 2 0x.. 1 0x.. 0 0x..<br />

1 void change(struct person *pp) {<br />

2 strcpy(pp->name, "Rudi Ratlos");<br />

3 pp->id = 987654;<br />

4 }<br />

1 struct person *pp = &rudi;<br />

2 change(pp);<br />

3 printf("%6d %s\n", pp->id, pp->name);<br />

1 struct node {<br />

2 int data;<br />

3 struct node *next;<br />

4 };<br />

1 struct node c = {0, NULL};<br />

2 struct node b = {1, &c};<br />

3 struct node a = {2, &b};<br />

4 struct node *lp = &a;<br />

5 printf("%d\n", lp->next->next->data);<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 88 / 326


<strong>Programmieren</strong> in C<br />

Typdefinition<br />

Typdefinitionen – typedef<br />

Typdefinition<br />

• Syntax: typedef <br />

• Danach Verwendung von <br />

statt möglich<br />

• Kein neuer Typ, nur ein weiterer<br />

Name für denselben Typ<br />

Vorteil<br />

• (Meist) Kürzer<br />

• Portabler, da Typdefinition nur an<br />

einer Stelle steht<br />

Beispiel<br />

• Keine neuen Typen nur neue Namen<br />

• struct knoten wäre auch ok<br />

• knoten und struct knoten ergeben<br />

kein Namensproblem<br />

1 typedef int ganzzahl;<br />

2 typedef enum {ROT, GELB, GRUEN} ampel;<br />

3 typedef struct _knoten *knotenzeiger;<br />

4 typedef struct _knoten {<br />

5 knotenzeiger next;<br />

6 int data;<br />

7 } knoten;<br />

8 typedef struct _node {<br />

9 struct _node *next;<br />

10 int data;<br />

11 } node;<br />

12 typedef node *nodeptr;<br />

1 knoten k1, k2;<br />

2 knotenzeiger kp = &k2;<br />

3 k1.next = kp;<br />

4 node n1, n2;<br />

5 nodeptr np = &n1;<br />

6 node *nq = &n2;<br />

7 np->next = nq;<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 89 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Freispeicherverwaltung<br />

Speicher anfordern<br />

• Es gibt kein new<br />

• Speicher mit malloc anfordern<br />

• Anzahl Bytes angeben<br />

• Adresse wird zurückgegeben<br />

• Freispeicher wird von Betriebsystem<br />

verwaltet<br />

Speicher freigeben<br />

• Es gibt keinen Garbage Collector<br />

• Speicher mit free freigeben<br />

• Adresse als Parameter angeben<br />

• Größe dem Betriebssystem bekannt<br />

• Danach Zugriff auf Speicher illegal<br />

• Achtung: Keine Compiler-Warnung<br />

• Achtung: (Nicht unbedingt gleich)<br />

Fehler zur Laufzeit<br />

1 int len=10, i;<br />

2 char *a = malloc(len*sizeof(char));<br />

3 for (i=0; i < len; i++) {<br />

4 a[i] = i;<br />

5 }<br />

6 free(a);<br />

7 a[0] = 17; /* illegal, Laufzeit */<br />

0x200<br />

a,0x100<br />

0 1 2 3<br />

4 5 6 7<br />

8 9<br />

0x200<br />

Freispeicher,<br />

Heap<br />

Stack<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 90 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Dynamische Speicherverwaltung<br />

Funktionen zur dynamischen Speicherverwaltung<br />

• void *malloc(size_t size)<br />

Reserviert einen size Byte großen Speicherblock<br />

• void *calloc(size_t nEle, size_t eleSize)<br />

Reserviert einen nEle * eleSize Byte großen Speicherblock und füllt ihn mit Nullen<br />

• void free(void *ptr)<br />

Gibt den vormals mit [mc]alloc allokierten Speicherbereich an der Adresse ptr an<br />

das System zurück<br />

Alles definiert in stdlib.h<br />

• size_t ist ein vorzeichenloser Ganzzahltyp<br />

Fehlerfall<br />

• Falls beim Allokieren kein Speicherblock mehr zur Verfügung steht wird NULL<br />

zurückgegeben<br />

• NULL ist ein Makro, Zeiger auf nicht definierten Wert, verwenden wie null in Java<br />

• NULL ist meist (nicht immer) so definiert: #define NULL ((void *) 0)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 91 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Keine Garbage-Collection<br />

Achtung Speicherlecks (leak)<br />

• Speicher wird nicht automatisch<br />

freigegeben<br />

• Jeder allokierte Block muss<br />

freigegeben werden<br />

$ leak<br />

Kein Speicher nach 80330 mallocs<br />

$ leak -f<br />

ok nach 100000 mallocs<br />

ok nach 200000 mallocs<br />

ok nach 300000 mallocs<br />

ok nach 400000 mallocs<br />

ok nach 500000 mallocs<br />

...<br />

ok nach 50000000 mallocs<br />

...<br />

1 #include <br />

2 #include <br />

3 #include <br />

4 int main(int argc, char *argv[]) {<br />

5 int len = 10000, *a, run=1, mallocs=0;<br />

6 while(run) {<br />

7 a = malloc(len*sizeof(int));<br />

8 if (a == NULL) {<br />

9 printf("Kein Speicher nach %d mallocs\n",<br />

10 mallocs);<br />

11 run = 0;<br />

12 }<br />

13 mallocs += 1;<br />

14 if (mallocs % 100000 == 0)<br />

15 printf ("ok nach %d mallocs\n", mallocs);<br />

16 if (argc > 1 &&<br />

17 strcmp(argv[1], "-f") == 0)<br />

18 free(a);<br />

19 } return 0; }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 92 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Speicherlecks erkennen<br />

Speicherlecks Beispiel<br />

• Beispiel ähnlich<br />

• Lecks ohne Option -f<br />

Speicherlecks erkennen mit valgrind<br />

• valgrind, memory checker<br />

• Instrumentieren von vorhandenem<br />

Code<br />

• Einfach vor Programmaufruf<br />

valgrind<br />

1 #include <br />

2 #include <br />

3 #include <br />

4<br />

5 int main(int argc, char *argv[]) {<br />

6 int len = 10000, run=1, mallocs=0, i;<br />

7 int *aptr;<br />

8 while(run && (mallocs < 1000)) {<br />

9 aptr = malloc(len*sizeof(int));<br />

10 for (i=0; i 1 &&<br />

14 strcmp(argv[1], "-f") == 0)<br />

15 free(aptr);<br />

16 }<br />

17 return 0;<br />

18 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 93 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

valgrind Beispiellauf<br />

$ valgrind ./leakval.exe<br />

==12615== Memcheck, a memory error detector<br />

==12615== HEAP SUMMARY:<br />

==12615== in use at exit: 40,000,000 bytes in 1,000 blocks<br />

==12615== total heap usage: 1,000 allocs, 0 frees, 40,000,000 bytes allocated<br />

==12615== LEAK SUMMARY:<br />

==12615== definitely lost: 40,000,000 bytes in 1,000 blocks<br />

==12615== indirectly lost: 0 bytes in 0 blocks<br />

==12615== possibly lost: 0 bytes in 0 blocks<br />

==12615== still reachable: 0 bytes in 0 blocks<br />

==12615== suppressed: 0 bytes in 0 blocks<br />

$ valgrind ./leakval.exe -f<br />

==12618== Memcheck, a memory error detector<br />

==12618== HEAP SUMMARY:<br />

==12618== in use at exit: 0 bytes in 0 blocks<br />

==12618== total heap usage: 1,000 allocs, 1,000 frees, 40,000,000 bytes allocated<br />

==12618== All heap blocks were freed -- no leaks are possible<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 94 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Verkettete Liste – Header<br />

Einfach verkettete Liste<br />

• Zeiger auf Nachfolger<br />

• Wert ist Feld mit 80 Zeichen<br />

• Merken des Zeigers auf das erste Feld<br />

zur Repräsentation der Liste<br />

Hilfsroutinen<br />

• Liste anzeigen, show_list:<br />

Durchlaufen und Zeichenkette<br />

9<br />

10<br />

} slist;<br />

typedef slist *slptr;<br />

11<br />

ausgeben<br />

12 void show_list(slptr l);<br />

• Listenelement am Anfang einfügen, 13 slptr insert(slptr list, const char *s);<br />

insert: String mit max 80 Zeichen wird14 void delete_list(slptr list);<br />

kopiert<br />

15 slptr copy_list_reverse(slptr first);<br />

• Liste löschen, delete_list: Erstes<br />

Element schrittweise löschen<br />

• Kopieren, copy_list_reverse: Kopie<br />

hat umgekehrte Reihenfolge<br />

1 #ifndef SLIST_H<br />

2 #define SLIST_H<br />

3<br />

4 #define SMAXLEN 80<br />

5<br />

16<br />

6 typedef struct _slist {<br />

7 struct _slist *next;<br />

8 char s[SMAXLEN];<br />

17 #endif<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 95 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Verkettete Liste – Implementierung/1<br />

1 void show_list(slptr lis) {<br />

2 for (; lis; lis = lis->next)<br />

3 printf("%s ", lis->s);<br />

4 printf("\n");<br />

5 }<br />

6<br />

7 static void scopy(char *dest, const char *src) {<br />

8 strncpy(dest, src, SMAXLEN);<br />

9 dest[SMAXLEN-1] = 0;<br />

0 }<br />

1<br />

2 slptr insert(slptr lis, const char *s) {<br />

3 slptr neu = malloc(sizeof(slist));<br />

4 if (neu == NULL)<br />

5 return NULL;<br />

6 scopy(neu->s, s);<br />

7 neu->next = lis;<br />

8 return neu;<br />

9 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 96 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Verkettete Liste – Implementierung/2<br />

1 void delete_list(slptr lis) {<br />

2 slptr next;<br />

3 while (lis) {<br />

4 next = lis->next;<br />

5 free(lis);<br />

6 lis = next;<br />

7 }<br />

8 }<br />

9<br />

0 slptr copy_list_reverse(slptr lis) {<br />

1 slptr nlis = NULL;<br />

2 while (lis) {<br />

3 nlis = insert(nlis, lis->s);<br />

4 lis = lis->next;<br />

5 }<br />

6 return nlis;<br />

7 }<br />

lis<br />

a<br />

c<br />

0x..<br />

0x..<br />

b<br />

b<br />

0x..<br />

0x..<br />

c<br />

nlis<br />

a<br />

0x..<br />

0x..<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 97 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Verkettete Liste – SelectionSort<br />

SelectionSort<br />

• Gibt neue sortierte Liste zurück<br />

• Sortieren durch Auswahl des größten Elements<br />

• Aufsteigend sortiert<br />

Anmerkungen<br />

• Auswahl des größten Elements, neue Liste von hinten aufgebaut, dass man das<br />

nächste (kleinere) immer vorne anfügen kann<br />

• Arbeiten auf Kopie, also zunächste Kopie erstellen, Reihenfolge egal (Zeile 4)<br />

• Kopfelement um Sonderfälle zu vermeiden, wird nie verschoben<br />

• Bestimme größtes Element (Zeile 10-14)<br />

• Hänge größtes Element aus und in neue Liste ein (Zeile 15-18)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 98 / 326


<strong>Programmieren</strong> in C<br />

Freispeicherverwaltung<br />

Verkettete Liste – SelectionSort, Implementierung<br />

1 slptr selection_sort(slptr lis) {<br />

2 if (lis == NULL) { return lis; }<br />

3 slptr cp_lis=copy_list_reverse(lis), start=NULL;<br />

4 slist _first; /* Kopfelement, es wird niemals damit verglichen */<br />

5 slptr first = &_first; first->next = cp_lis;<br />

6 while (first->next) {<br />

7 slptr befmax=first, lis=first, hlis;<br />

8 while (lis->next) { /* Finde Maximales */<br />

9 if (strcmp(lis->next->s, befmax->next->s) > 0) {<br />

0 befmax = lis;<br />

1 }<br />

2 lis = lis->next;<br />

3 }<br />

4 hlis = befmax->next->next; /* Max. an Anfang der neuen Liste */<br />

5 befmax->next->next = start;<br />

6 start = befmax->next;<br />

7 befmax->next = hlis;<br />

8 }<br />

9 return start;<br />

0 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 99 / 326


<strong>Programmieren</strong> in C<br />

Varianten/Unions<br />

Varianten/Unions<br />

Ziel – Wenig Speicherplatz<br />

• Nur eine von mehreren Varianten<br />

• Bei struct müsste für alle Platz<br />

vorgehalten werden<br />

Variante – union<br />

• Syntax wie struct, aber union<br />

• Alle Komponenten erhalten dieselbe<br />

Anfangsadresse im Speicher<br />

• Bei struct hintereinander<br />

• Nur eine Variante ist gültig<br />

• Nur diese sollte verwendet werden<br />

• Leider sind alle verwendbar mit dann<br />

meist sinnlosen Werten<br />

• Größe ist die Größe der größten<br />

Variante<br />

1 union zahl {<br />

2 int i;<br />

3 char c[12];<br />

4 double d;<br />

5 };<br />

1 union zahl z1;<br />

2 z1.i = 42;<br />

3 printf("%12d ", z1.i);<br />

4 strcpy(z1.c, "42");<br />

5 printf("%12s ", z1.c);<br />

6 printf("%12d ", z1.i);<br />

7 printf("%12g\n", z1.d);<br />

42 42 12852 4.85435e-270<br />

4 2 \0<br />

12852<br />

4.85435e-270<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 100 / 326


<strong>Programmieren</strong> in C<br />

Varianten/Unions<br />

Beispiel – Varianten von Personen/1<br />

Zwei Personentypen<br />

• Studierende, STUD<br />

• Professoren, PROF<br />

Abbildung mit struct und union<br />

• Ein struct mit Klassifikator was das<br />

für eine Variante ist<br />

• union aus structs mit den Varianten<br />

1 enum typ { STUD, PROF };<br />

2<br />

3 struct person {<br />

4 enum typ was;<br />

5 union {<br />

6 struct {<br />

7 int matnr;<br />

8 double notenschnitt;<br />

9 int semester;<br />

10 } studi;<br />

11 struct {<br />

12 int persnr;<br />

13 int seitjahr;<br />

14 } prof;<br />

15 } details;<br />

16 };<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 101 / 326


<strong>Programmieren</strong> in C<br />

Varianten/Unions<br />

Beispiel – Varianten von Personen/2<br />

Erstellung von zwei Personen<br />

• Eine Studierende Susi<br />

• Ein Professor Roland<br />

Ausgabe, nächste Seite<br />

1 struct person susi;<br />

2 struct person roland;<br />

3<br />

4 susi.was = STUD;<br />

5 susi.details.studi.matnr = 123456;<br />

6 susi.details.studi.notenschnitt = 1.6;<br />

7 susi.details.studi.semester = 3;<br />

8<br />

9 roland.was = PROF;<br />

10 roland.details.prof.persnr = 654321;<br />

11 roland.details.prof.seitjahr = 1418;<br />

12<br />

13<br />

14 show(&susi);<br />

15 show(&roland);<br />

123456 1.6 3<br />

654321 1418<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 102 / 326


<strong>Programmieren</strong> in C<br />

Varianten/Unions<br />

Beispiel – Varianten von Personen/3<br />

Ausgabe von Personen<br />

• Je nach Variante unterschiedlich<br />

1 void show(struct person *p) {<br />

2 switch (p->was) {<br />

3 case STUD:<br />

4 printf("%6d %4.2g %1d\n",<br />

5 p->details.studi.matnr,<br />

6 p->details.studi.notenschnitt,<br />

7 p->details.studi.semester);<br />

8 break;<br />

9 case PROF:<br />

10 printf("%6d %4d\n",<br />

11 p->details.prof.persnr,<br />

12 p->details.prof.seitjahr);<br />

13 break;<br />

14 }<br />

15 }<br />

123456 1.6 3<br />

654321 1418<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 103 / 326


<strong>Programmieren</strong> in C<br />

Bitfelder<br />

Bitfelder<br />

1 struct punkt {<br />

Ziel – Wenig Speicherplatz<br />

2 /* XY-Position: 0-1024 */<br />

• Mehrere Zahlen mit kleinem<br />

3 unsigned x:10;<br />

Zahlenbereich kompakt repräsentieren 4 unsigned y:10;<br />

Umsetzung – Bitfelder<br />

• Syntax wie struct<br />

• Komponenten<br />

unsigned : <br />

• Es werden Anzahl für Zahl<br />

reserviert<br />

• statt unsigned auch signed möglich<br />

Zugriff<br />

• Punkt-Notation<br />

• Compiler übernimmt Bit-Shifterei<br />

• Achtung: Aktuelles Speicherlayout<br />

implementierungsabhängig<br />

5 /* RGB-Anteile: 0-255 */<br />

6 unsigned r:8;<br />

7 unsigned g:8;<br />

8 unsigned b:8;<br />

9 };<br />

x y r g b<br />

6-8 Byte je Punkt<br />

statt 20 (int) oder 10-12, 16 (short)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 104 / 326


<strong>Programmieren</strong> in C<br />

Bitfelder<br />

Bitfelder – Verwendung<br />

x y r g b<br />

1 struct punkt weissediagonale[1024];<br />

2 int i;<br />

3 for (i=0; i < 1024; i++) {<br />

4 weissediagonale[i].x = i;<br />

5 weissediagonale[i].y = i;<br />

6 weissediagonale[i].r =<br />

7 weissediagonale[i].g =<br />

8 weissediagonale[i].b = 255;<br />

9 }<br />

0 printf("%ld\n", sizeof weissediagonale);<br />

8192, entspricht 8 Byte, Trennung an Wortgrenze<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 105 / 326


<strong>Programmieren</strong> in C<br />

Funktionszeiger<br />

Funktionszeiger<br />

Ziel – Parametrisiertes Verhalten<br />

• Keine Objektorientierung<br />

• Funktionalität zuordnen/kapseln<br />

können<br />

Umsetzung – Zeiger auf Funktion<br />

• Parametervereinbarung wie gewohnt<br />

• Statt Funktionsname den<br />

Namen des Funktionszeigers in<br />

Klammern mit einem Stern davor<br />

• (*)<br />

Aufruf<br />

• Inhaltsoperator<br />

• Geht auch direkt mit Namen,<br />

was sonst sollte gemeint sein<br />

1 char g1[] = "Hallo";<br />

2 char g2[] = "Hey Depp";<br />

3<br />

4 char *nett(void) { return g1; }<br />

5 char *boese(void) { return g2; }<br />

6<br />

7 typedef char *(*grusstyp)(void);<br />

1 char *(*gruss1)(void);<br />

2 grusstyp gruss2;<br />

3<br />

4 gruss1 = nett;<br />

5 printf("%s, wie geht es?\n", (*gruss1)())<br />

6 printf("%s, wie geht es?\n", gruss1());<br />

7 gruss2 = boese;<br />

8 printf("%s, wie geht es?\n", gruss2());<br />

Hallo, wie geht es?<br />

Hallo, wie geht es?<br />

Hey Depp, wie geht es?<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 106 / 326


<strong>Programmieren</strong> in C<br />

Funktionszeiger<br />

Funktionszeiger – Beispiel qsort<br />

Quicksort<br />

• Bibliotheksfunktion qsort<br />

• Funktioniert für Felder von<br />

beliebigem Datentyp<br />

• Vergleichsfunktion muss<br />

übergeben werden<br />

Vergleichsfunktion<br />

• Gibt int zurück<br />

< 0 wenn kleiner, > 0 wenn<br />

größer, = 0 wenn gleich<br />

• Parameter sind Zeiger auf zu<br />

vergleichende Werte<br />

2 5 3<br />

2 3 5<br />

5 3 2<br />

• void *, jeder Typ<br />

• const Wert wird nicht geändert<br />

1 void show(int a[], int len) {<br />

2 int i;<br />

3 for (i=0; i < 3; i++)<br />

4 printf("%d ", a[i]);<br />

5 printf("\n");<br />

6 }<br />

7 int kleiner(const void *e1, const void *e2) {<br />

8 return *((int *) e1) - *((int *) e2);<br />

9 }<br />

10 int groesser(const void *e1, const void *e2) {<br />

11 return *((int *) e2) - *((int *) e1);<br />

12 }<br />

1 int a[3] = { 2, 5, 3 };<br />

2 show(a,3);<br />

3 qsort(a, 3, sizeof (int), kleiner);<br />

4 show(a,3);<br />

5 qsort(a, 3, sizeof (int), groesser);<br />

6 show(a,3);<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 107 / 326


<strong>Programmieren</strong> in C<br />

Makros<br />

Makros – Präprozessor<br />

• #include: Dateien einfügen<br />

• #define: Ersetzen von Text<br />

• #ifdef, #ifndef, #if defined, #if !defined, #if, #else, #elif, #endif, . . .<br />

Bedingte Übersetzung<br />

• Beispiel: Include-Guards<br />

• Beispiel: /usr/include/stdio.h<br />

1 #ifdef __USE_GNU<br />

2<br />

3 #endif<br />

1 #if defined __GNUC__ || defined __USE_GNU<br />

2<br />

3 #endif<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 108 / 326


<strong>Programmieren</strong> in C<br />

Makros<br />

Makros – Ersetzen von Text<br />

Ersetzen von Text<br />

• #define <br />

3 int main(void) {<br />

• wird durch ersetzt<br />

4 int iPI=0;<br />

• Ersetzungen finden weder innerhalb 5 char *s = " PI ist cool";<br />

von Zeichenketten statt noch innerhalb 6 printf("%g\n", PI);<br />

von Bezeichnern<br />

7 return 0;<br />

Verwendung<br />

• Wird auch für Konstanten verwendet,<br />

vermeiden wegen fehlender<br />

Typprüfung<br />

• Sinnvoll zum Beispiel für<br />

Parametrisieren von Typen<br />

makros.c<br />

1 #include <br />

2 #define PI 3.1415<br />

8 }<br />

1 $ ./makros<br />

2 3.1415<br />

3 $ gcc -E makros.c | tail<br />

4 # 940 "/usr/include/stdio.h" 3 4<br />

5 # 2 "makrosa.c" 2<br />

6 int main(void) {<br />

7 int iPI=0;<br />

8 char *s = " PI ist cool";<br />

9 printf("%g\n", 3.1415);<br />

10 return 0;<br />

11 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 109 / 326


<strong>Programmieren</strong> in C<br />

Makros<br />

Makros – Parameter<br />

Makros mit Parametern<br />

• Syntax:<br />

#define (, ..., ) \<br />

<br />

• Kein Leerzeichen zwischen Namen<br />

und Klammer auf(<br />

• Verwenden der Parameternamen im<br />

<br />

Rein textuelle Ersetzung<br />

• Keine Typen, also keine<br />

Typüberprüfung<br />

• Achtung bei Ausdrücken, nur textuelle<br />

Ersetzung!<br />

• Im Beispiel geht etwas mit der<br />

Operatorpräzedenz schief<br />

1 #include <br />

2<br />

3 #define add1(i,j) i+j<br />

4 #define mul1(i,j) i*j<br />

1 int i=3, j=4;<br />

2 printf("%d\n", mul1(i, j)); /* 12 */<br />

3 printf("%d\n", add1(i, j)); /* 7 */<br />

4 printf("%d\n", mul1(i+1, j)); /* 7 */<br />

5 printf("%d\n", add1(i, j)*2); /* 11 */<br />

Zeile 4: Ergebnis 7 statt 16<br />

i+1*j<br />

Zeile 5: Ergebnis 11 statt 14<br />

i+j*2<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 110 / 326


<strong>Programmieren</strong> in C<br />

Makros<br />

Makros – Parameter, Klammern<br />

Klammerung der Parameter vermeidet<br />

manche Probleme<br />

Leider nicht alle<br />

1 #define add2(i,j) ((i) + (j))<br />

2 #define mul2(i,j) ((i) * (j))<br />

1 int i=3, j=4;<br />

2 printf("%d\n", mul2(i, j)); /* 12 */<br />

3 printf("%d\n", add2(i, j)); /* 7 */<br />

4 printf("%d\n", mul2(i+1, j)); /* 16 */<br />

5 printf("%d\n", add2(i, j)*2); /* 14 */<br />

6<br />

7 printf("%d\n", add2(++i, ++i)*2); /* 20 *<br />

Zeile 7: Ergebnis 20 statt 18 ???<br />

((++i) + (++i))*2<br />

Seiteneffekte, was soll rauskommen?<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 111 / 326


<strong>Programmieren</strong> in C<br />

Makros<br />

Makros – Parameter, Klammern, Seiteneffekte<br />

Makros können Mehrfachverwendung mit<br />

1 #define quad(i) ((i)*(i))<br />

unerwünschten Seiteneffekten kaschieren<br />

Nicht machen<br />

1 int i=3;<br />

inline-Funktionen im Header verwenden 2 printf("%d\n", quad(++i)); /* 25 */<br />

ab C99<br />

3 printf("%d\n", i); /* 5 */<br />

Zeile 2: Ergebnis 25 statt 16 ???<br />

((++i) * (++i))<br />

Niemand sieht und erwartet im Quellcode<br />

die doppelte Erhöhung von i.<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 112 / 326


<strong>Programmieren</strong> in C<br />

Konstanten<br />

Konstanten<br />

Konstanten<br />

• Syntax: const ...<br />

• Modifizierer des Typs<br />

• Compiler stellt sicher, dass der Wert<br />

nicht geändert werden kann<br />

Statt #define besser const verwenden<br />

• Typüberprüfung findet statt<br />

• Achtung: In Headern als extern<br />

deklarieren ohne Wert und Wert in<br />

einer Übersetzungseinheit definieren<br />

• Alternative: enum für Feldgrößen da<br />

const dort nicht erlaubt<br />

1 #include "constlib.h"<br />

2<br />

3 #define ANTWORT 42<br />

4 const int ANSWER=42;<br />

5<br />

6 #define AGROESSE 100;<br />

7 enum { ASIZE=100 };<br />

8 char s[ASIZE];<br />

constlib.h<br />

1 #ifndef CONSTLIB_H<br />

2 #define CONSTLIB_H<br />

3 extern const int THEANSWER;<br />

4 #endif<br />

constlib.c<br />

1 #include "constlib.h"<br />

2 const int THEANSWER=42;<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 113 / 326


<strong>Programmieren</strong> in C<br />

Konstanten<br />

Konstanten und Zeiger<br />

Konstanten und Zeiger<br />

• const char *<br />

(veränderbarer) Zeiger auf konstantes<br />

Zeichen<br />

• char *const<br />

Konstanter Zeiger auf (veränderbares)<br />

Zeichen<br />

• const char *const<br />

Konstanter Zeiger auf konstantes<br />

Zeichen<br />

1 char s[100];<br />

2<br />

3 const char *a = s;<br />

4 /* a[0] = ’x’; verboten */<br />

5 a = s+1; /* ok */<br />

6<br />

10<br />

7 char *const b = s;<br />

8 b[0] = ’x’; /* ok */<br />

9 /* b = s+1; verboten */<br />

11 const char *const c="Fixer String";<br />

12 /* c[0] = ’x’; verboten */<br />

13 /* c = s+1; verboten */<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 114 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard-Bibliothek – Übersicht<br />

Standard-Bibliothek – Auszug<br />

• assert.h: Zusicherungen<br />

• ctype.h: Klassifizierung und Konversion von Zeichen<br />

• math.h: Mathematische Funktionen<br />

• stdarg.h: Variable Parameterlisten<br />

• stdio.h: Ein-/Ausgabe<br />

• stdlib.h: Speicherverwaltung, Stringkonvertierung, Zufallszahlen, . . .<br />

• string.h: String-/Speicherbearbeitung<br />

• time.h: Datum und Uhrzeit<br />

• ....<br />

Teil von ANSI-C / ISO-C<br />

• Syntax und Verhalten definiert<br />

• Meist plattformunabhängig, Unterstützung für Plattformabhängigkeiten (wenn man<br />

will/muss kann man plattformunabhängigen Code schreiben)<br />

• Viele weitere Bibliotheken (außerhalb des Standards) verfügbar<br />

Dokumentation: man <br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 115 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard-Bibliothek – assert<br />

Zusicherungen<br />

• assert()<br />

• Makro in assert.h<br />

• Falls Bedingung nicht erfüllt ist, dann<br />

wird Programm mit entsprechender<br />

Meldung abgebrochen.<br />

Übersetzung<br />

• Kein Code für assert, wenn die<br />

Konstante NDEBUG definiert ist.<br />

• Programm läuft schneller<br />

• Makros können mit Compiler-Option<br />

gesetzt werden<br />

• -DNDEBUG<br />

• In Makefile verwendbar, CFLAGS<br />

1 #include <br />

2 #include <br />

3 int mydiv(int zaehler, int nenner) {<br />

4 assert (nenner != 0);<br />

5 return zaehler/nenner;<br />

6 }<br />

7 int main(void) {<br />

8 printf("%d\n", mydiv(17,2));<br />

9 printf("%d\n", mydiv(17,0));<br />

10 return 0; }<br />

$ gcc assert.c -o assert<br />

$ ./assert<br />

8<br />

assert.exe: assert.c:5: div:<br />

Assertion ‘nenner != 0’ failed.<br />

Aborted<br />

$ gcc -DNDEBUG assert.c -o assert<br />

8<br />

Floating point exception<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 116 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard-Bibliothek – Standard I/O<br />

Zeiger auf Ströme<br />

• stdin (Eingabe), stdout (Ausgabe), stderr (Fehler)<br />

High-Level – gepuffert<br />

• FILE * (Zeiger auf Strom)<br />

• printf, scanf; fprintf, fscanf (Dateien);<br />

sprintf, sscanf (Strings)<br />

• puts, putc, gets, getchar, getc, fputs, fgetc (s String,<br />

c Char)<br />

• fopen, fclose (Dateien); fread, fwrite (binär), . . .<br />

• man stdio<br />

Low-Level – ungepuffert<br />

• int (handle)<br />

• Nicht Teil des ISO-Standards, POSIX-Standard (Unix)<br />

• open, creat, close, unlink, read, write, lseek, . . .<br />

stdin stdout<br />

Programm<br />

stderr<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 117 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard I/O – Beispiel, Datei I/O /1<br />

Ziel<br />

• Datei einlesen, optional<br />

Dateiname als<br />

Kommandzeilenparameter,<br />

sonst stdin<br />

• Datei out.strip schreiben<br />

• Zeilenweise<br />

• Innerhalb einer Zeile keine<br />

Wiederholungen von<br />

Whitespaces<br />

Umsetzung<br />

• stdio, ctype<br />

• Kommaoperator vermeiden<br />

1 #include <br />

2 #include <br />

3<br />

4 const char *outfname = "out.strip";<br />

5<br />

6 int main(int argc, char *argv[]) {<br />

7 FILE *fpin = stdin;<br />

8 FILE *fpout = fopen(outfname, "w");<br />

9 int last_space = 0;<br />

10<br />

11 if (argc >= 2) {<br />

12 fpin = fopen(argv[1], "r");<br />

13 }<br />

14 if (!fpin || !fpout) {<br />

15 fprintf(stderr, "oopps\n");<br />

16 return -1;<br />

17 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 118 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard I/O – Beispiel, Datei I/O /2<br />

1 while (!feof(fpin)) {<br />

2 int c = fgetc(fpin);<br />

3 if (c == EOF)<br />

4 break;<br />

5 if (isspace(c)) {<br />

6 last_space=1;<br />

7 if (c == ’\n’)<br />

8 fputc(c, fpout), last_space = 0;<br />

9 } else {<br />

10 if (last_space) {<br />

11 fputc(’ ’, fpout); last_space = 0;<br />

12 }<br />

13 fputc(c, fpout);<br />

14 }<br />

15 }<br />

16 fclose(fpin); fclose(fpout);<br />

17 return 0;<br />

18 }<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 119 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Standard-Bibliothek – Speicherblöcke und Strings<br />

Speicherfunktionen, extra Parameter size<br />

• memchr: Puffer nach Zeichen durchsuchen<br />

• memcmp: Speicherblöcke vergleichen<br />

• memmove: Speicherblock verschieben<br />

• memset: Speicher füllen<br />

Stringfunktionen, nur Anfangsadresse (n max. Zeichen)<br />

• strcat, strncat: Zeichenkette anhängen<br />

• strchr: String nach Zeichen durchsuchen<br />

• strcmp, strncmp: String vergleichen<br />

• strcpy, strncpy: String kopieren<br />

• strdup: String kopieren, neuer Speicher<br />

• strlen: Länge eines Strings<br />

• strstr: Nach Teilstring suchen<br />

• . . .<br />

Speicherfunktionen<br />

0x..0x..0x..0x..0x..0x..<br />

Speicherblöcke beliebiger Länge,<br />

beliebige Struktur (void *)<br />

Stringfunktionen<br />

H A L L O \0<br />

Speicherblöcke beliebiger Länge,<br />

0-terminiert, aus Zeichen (char *)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 120 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Strings – Beispiel /1<br />

Ziel<br />

• Zeichenkette der<br />

Kommandozeile zu einem<br />

dynamisch allokierten String<br />

zusammenfügen<br />

Umsetzung<br />

• string-Funktionen<br />

• stdlib-Funktionen<br />

Bemerkung<br />

• Viele strlen-Aufrufe nicht<br />

effizient<br />

• Was ist die Komplexität? Wie<br />

geht es besser?<br />

1 #include <br />

2 #include <br />

3 #include <br />

4<br />

5 int main(int argc, char *argv[]) {<br />

6 int i;<br />

7 int len=1;<br />

8 char *s = malloc(sizeof(char));<br />

9 s[0] = 0;<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 121 / 326


<strong>Programmieren</strong> in C<br />

Standard-Bibliothek<br />

Strings – Beispiel /2<br />

Komplexität<br />

• Aufwendig wegen strlen<br />

• Viele Allokationen trotz Trick mit<br />

Verdopplung<br />

• Kopieren eines immer wieder<br />

wachsenden Teils<br />

Besser<br />

• Zweimal durchlaufen, einmal<br />

Speicher berechnen, dann<br />

allokieren und füllen<br />

• Linear<br />

1 for (i=1; i


<strong>Programmieren</strong> in Python<br />

Einführung<br />

Python<br />

Pseudocode that runs<br />

Was ist Python?<br />

• Objektorientierte <strong>Skript</strong>sprache (“Perl by a sane person”)<br />

• Einfach erlernbar (Einsteigersprache), interaktiv, Open Source<br />

• Um Größenordnung schnellere Entwicklung, auch für Prototypen geeignet<br />

• Plattformunabhängig, interpretiert, Bytecode (JIT mit pypy)<br />

Features<br />

• Dynamische Typisierung, Garbage Collection<br />

• Eingebaute Datenstrukturen (Listen, Tupel, Dictionaries, String, . . . )<br />

• Mächtige Ausdrucksweise und Werkzeuge (Verketten, abbilden, slicen)<br />

• Klassische Kontrollstrukturen (imperativ), Objektorientierung und funktionale<br />

Primitive<br />

• Unterstützung für große Projekte (Module, Ausnahmen, . . . )<br />

• Integration (C, C++, Java, XMLRPC, REST, SOAP, . . . )<br />

• Bibliotheken (Web, Email, reguläre Ausdrücke, XML, GUI, Threading, Unittesting,<br />

Bildbearbeitung, . . . )<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 123 / 326


<strong>Programmieren</strong> in Python<br />

Einführung<br />

Historie<br />

Background<br />

• Treibende Kraft: Guido van Rossum, BDFL<br />

• Name von “Monty Python Flying Circus”<br />

Historie<br />

90: Als <strong>Skript</strong>sprache für verteiltes BS konzipiert<br />

91: Erste Veröffentlichung<br />

94: comp.lang.python<br />

Heute<br />

Implementierungen:<br />

99: Jython, Java VM<br />

01: psyco, native Code<br />

06: IronPython, .Net<br />

07: PyPy, Python in Python, JIT<br />

10: Python on Android<br />

• Aktuell CPython 2.7/3.3, jython 2.7a, IronPython 2.7, PyPy 1.9 (2.7)<br />

• Aktive Entwicklergemeinde, sehr viele Bibliotheken, python.org<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 124 / 326


<strong>Programmieren</strong> in Python<br />

Einführung<br />

Verbreitung<br />

Plattform für Anwendungen<br />

• Hunderte <strong>Skript</strong>e in /usr/bin<br />

• Blender, Maya: 3D-Graphik<br />

• Mercurial: Versionsmanagement<br />

• Trac: Projekt/Software Management<br />

• Google App Engine, Django,<br />

Raspberry Pi<br />

Interner Einsatz<br />

• Google, NASA, Yahoo, ILM<br />

Entwickler<br />

• Sehr weit verbreitet<br />

• Die meist genutzte “general purpose”<br />

<strong>Skript</strong>sprache<br />

• Top Ten in TIOBE<br />

http://www.tiobe.com/index.php/content/<br />

paperinfo/tpci/index.html<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 125 / 326


<strong>Programmieren</strong> in Python<br />

Einführung<br />

Umgebung<br />

Interpreter und Tools<br />

• www.python.org/2.7.3<br />

• Integrierte Entwicklungsumgebung<br />

(IDLE), und interaktiver Interpreter<br />

Interaktive “Shell” in IDLE<br />

• Lernen der Sprache<br />

• Experimentieren mit der Bibliothek<br />

• Testen der eigenen Programme<br />

• Auswerten von allen Ausdrücken<br />

Alternativen: Emacs, eclipse pydev<br />

Online-Lektüren (neben Buch)<br />

• docs.python.org/2/tutorial/<br />

• wiki.python.org/moin/BeginnersGuide<br />

• pythonchallenge.com, checkio.org<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 126 / 326


<strong>Programmieren</strong> in Python<br />

Einführung<br />

IDLE Übersicht<br />

Interaktive Shell und Editoren<br />

• Im Editor mit F5 Programm in<br />

interaktiver Shell ausführen<br />

• Interaktive Shell ist kein Editor<br />

Integrierter Debugger<br />

• Stop, Over, Out<br />

• Mitlaufen Source<br />

• Anzeige Stack, lokale/globale<br />

Variablen<br />

• Seltener benötigt als in C<br />

• Interaktives Testen<br />

• Weniger Fehler in Python ;-)<br />

Alternativen<br />

• Emacs: solide, interaktiv<br />

• Eclipse pydev: mächtig, nicht interaktiv<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 127 / 326


<strong>Programmieren</strong> in Python<br />

Einführung<br />

Encoding bei Python <strong>Skript</strong>en – Unicode einstellen<br />

Angabe der Zeichenkodierung<br />

• Erste Zeile im <strong>Skript</strong><br />

# -*- coding: -*-<br />

oder zweite Zeile, falls erste<br />

#!/usr/bin/python<br />

• Spezieller Kommentar<br />

• Teilt python (und IDLE) das Encoding<br />

des Quelltexts mit<br />

Verfügbare Zeichenkodierungen<br />

• utf-8, empfohlen<br />

• Unicode: alle Sprachen<br />

• Ab Python 3.0 Standard<br />

• Sehr stark empfohlen<br />

• iso-8859-1, vermeiden<br />

1 #!/usr/bin/python<br />

2 # -*- coding: utf-8 -*-<br />

3<br />

4 print "Hello Python World"<br />

1 Shebang: Starte den<br />

Python-Interpreter mit dem folgenden<br />

Zeilen als interaktive Eingabe<br />

2 Encoding: Der ganze Quelltext,<br />

inklusive Kommentare und den Texten<br />

in Strings, ist in dem angegebenen<br />

Encoding<br />

Alle ausführbaren Programme<br />

mit Zeilen 1 und 2 beginnen<br />

• Standard Westeuropa, latin1<br />

• Böse: Mac-Roman, cp1285<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 128 / 326


<strong>Programmieren</strong> in Python<br />

Erste Schritte<br />

Erste Schritte – Zahlen und Ausdrücke<br />

1 >>> print "Hallo Python Welt"<br />

2 Hallo Python Welt<br />

3<br />

4 >>> # Kommentare<br />

5<br />

6<br />

7 >>> 2 # Integer-Zahlen<br />

8 2<br />

9<br />

0 >>> 3.14 # Fliesskommazahlen<br />

1 3.14<br />

2<br />

3 >>> "String" # Zeichenketten<br />

4 ’String’<br />

5<br />

6 >>> 0xff # Hex<br />

7 255<br />

8<br />

9 >>> 0377 # Oktal<br />

0 255<br />

1 >>> 6+2 # Ausdruecke<br />

2 8<br />

3<br />

4 >>> 6*2<br />

5 12<br />

6<br />

7 >>> 6/2<br />

8 3<br />

9<br />

10 >>> 6/5 # Vorgabe ganzzahlig (2.x)<br />

11 1<br />

12<br />

13 >>> 6//5 # Explizit ganzzahlig ([23].x)<br />

14 1<br />

15<br />

16 >>> 3**4 # Exponenten<br />

17 81<br />

18<br />

19 >>> 3+1j # Komplexe Zahlen<br />

20 (3+1j)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 129 / 326


<strong>Programmieren</strong> in Python<br />

Erste Schritte<br />

Erste Schritte – Zuweisungen und Tests<br />

1 >>> x = 1 # Variablenzuweisung<br />

2 >>> x # hat den zugewiesenen Wert<br />

3 1<br />

4<br />

5 >>> x = y = 2 # Mehrfachzuweisung<br />

6 >>> x<br />

7 2<br />

8 >>> y<br />

9 2<br />

0<br />

1 >>> abs(-3) # eingebaute Funktionen<br />

2 3<br />

3<br />

4 >>> 0 < 1 # Tests<br />

5 True<br />

6 >>> 1 < 0<br />

7 False<br />

1 >>> True == 1 # Bool neuer Typ<br />

2 True<br />

3 >>> False == 0<br />

4 True<br />

5<br />

6 >>> 0 < 5 < 10 # Mehrfachtest<br />

7 True<br />

8<br />

9 >>> True and False<br />

10 False<br />

11 >>> True or False<br />

12 True<br />

13<br />

14 >>> not "eins"<br />

15 False<br />

16 >>> not False<br />

17 True<br />

18<br />

19 >>> "eins" and "zwei" # letzter Wert<br />

20 ’zwei’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 130 / 326


<strong>Programmieren</strong> in Python<br />

Erste Schritte<br />

Erste Schritte – Binäres Rechnen und Division<br />

1 >>> x = 2 # binaer ...000010<br />

2<br />

3 >>> x >> x & 0xff # binaeres Und<br />

7 2<br />

8<br />

9 >>> x | 1 # binaeres Oder<br />

0 3<br />

1<br />

2 >>> ~x # Komplement<br />

3 -3<br />

4<br />

5 >>> x^3 # binaeres XOR<br />

6 1<br />

1 >>> 3/2 # ganzzahlige Division (2.x)<br />

2 1<br />

3 >>> 3//2 # ganzzahlige Division ([23].x)<br />

4 1<br />

5 >>> 3.0/2 # Hochkonvertieren<br />

6 1.5<br />

7 >>> 3.0//2 # Abschneiden<br />

8 1.0<br />

9 >>> 3./2 # 0 nicht notwendig<br />

10 1.5<br />

11 >>> 10 % 3 # Module, Rest<br />

12 1<br />

13 >>> 10 // 3 # ganzzahlig<br />

14 3<br />

15 >>> 3*(10//3) + (10%3)<br />

16 10<br />

17 >>> 10.0//3 # erzwungen ganzzahlig<br />

18 3.0 # anderer Typ<br />

19 >>> 10.0/3<br />

20 3.3333333333333335<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 131 / 326


<strong>Programmieren</strong> in Python<br />

Erste Schritte<br />

Große Zahlen und Konvertierung<br />

1 >>> 3e10 # Exponentenschreibweise<br />

2 30000000000.0<br />

3<br />

4 >>> 2**10 # Potenzieren<br />

5 1024<br />

6 >>> 2**20 # grosse ganze Zahl<br />

7 1048576<br />

8 >>> 2**1000 # sehr grosse ganze Zahl<br />

9 107150860718626732094842504906000181<br />

0 056140481170553360744375038837035105<br />

1 112493612249319837881569585812759467<br />

2 291755314682518714528569231404359845<br />

3 775746985748039345677748242309854210<br />

4 746050623711418779541821530464749835<br />

5 819412673987675591655439460770629145<br />

6 711964776865421676604298316526243868<br />

7 37205668069376L<br />

1 >>> 3L # explizit grosse Zahlen<br />

2 3L<br />

3 >>> float(3) # explizite Konvertierung<br />

4 3.0 # in double<br />

5 >>> int(3.0) # und zurueck<br />

6 3<br />

7 >>> long(3.0) # explizite Konvertierung<br />

8 3L<br />

9 >>> int("12") # auch fuer Strings<br />

10 12<br />

11 >>> int("11", 16) # explizite Basis<br />

12 17<br />

13<br />

14 >>> int("zwoelf") # nur wenn moeglich<br />

15 # ansonsten Ausnahme<br />

16 Traceback (most recent call last):<br />

17 File "", line 1, in <br />

18 ValueError: invalid literal for int()<br />

19 with base 10: ’zwoelf’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 132 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Zahlen<br />

Zahlen und Operationen<br />

Zahlentypen<br />

• ganze Zahlen, int und long (beliebig lang)<br />

• Gleitkommazahlen, float mit double Genauigkeit,<br />

komplexe Zahlen<br />

• Intuitive Darstellung und Eingabe<br />

Alle üblichen arithmetischen Operationen<br />

• Standardarithmetik: +, -, * , /, ** , %, //<br />

• Logische Arithmetik: ~, ^, |, &, <br />

• Vorrangregeln und Klammern wie gewohnt<br />

1 Python 2.7.3<br />

2 >>> 3/2<br />

3 1<br />

4 >>> 3//2<br />

5 1<br />

1 Python 3.2.3 ...<br />

2 >>> 3/2<br />

3 1.5<br />

4 >>> 3//2<br />

5 1<br />

Boolesche Werte: False, True<br />

• Entspricht 0 und 1 (Historie)<br />

1<br />

2<br />

>>> 0 or ""<br />

or "Hallo"<br />

• Oder leerer String, nichtleerer String, . . .<br />

3 or "Welt"<br />

Logische Ausdrücke: and, or, not<br />

• Erstes bestimmendes Element wird zurück gegeben<br />

• Die andere Argumente werden nicht ausgewertet<br />

4 ’Hallo’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 133 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Zahlen<br />

Ausdrücke<br />

Aufrufe von Funktionen und Methoden<br />

• Funktionsaufrufe<br />

• Methodenaufrufe<br />

• Interaktive Ausgabe des Wertes<br />

• Zusammengesetzte Ausdrücke<br />

• Bereichstests<br />

Werte ausgeben in der interaktiven<br />

Kommandozeile<br />

• Zuweisungen haben keinen Wert<br />

• Wert von Ausdrücken wird<br />

ausgegeben<br />

• print für explizite Ausgabe<br />

1 >>> lis = [3,1,2]<br />

2 >>> len(lis) # Funktionsaufruf<br />

3 3<br />

4 >>> lis.append(8) # Methode<br />

5 >>> lis # Ausgabe<br />

6 [3, 1, 2, 8]<br />

7 >>> len(lis) < 6 and len(lis)<br />

8 # Zusammengesetzt<br />

9 4<br />

10 >>> 1 < len(lis) < 8 # Bereich<br />

11 True<br />

1 >> lis<br />

2 [3, 1, 2]<br />

3 >>> print lis # 2.x<br />

4 [3, 1, 2]<br />

5 >>> print(lis) # 2.x, 3.x<br />

6 [3, 1, 2]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 134 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Zahlen<br />

Ausgabe mit print<br />

Ausgabe von Objekten mit print<br />

• Lesbare Ausgabe von Objekten<br />

• Ausgabe aller Objekte durch<br />

Leerzeichen getrennt<br />

• Mit Komma am Ende wird<br />

Zeilenumbruch unterdrückt<br />

• Ausgabe mit Formatstring, wie in C,<br />

%-Operator<br />

• Python 3.x, nur noch in Klammern<br />

(jetzt schon möglich)<br />

Alternative<br />

• Ausgabe wie in Java<br />

1 >>> lis = [1,2,3]<br />

2 >>> print lis, "zwei", 4<br />

3 [1, 2, 3] zwei 4<br />

4 >>> print lis,"zwei",4; print "weiter"<br />

5 [1, 2, 3] zwei 4<br />

6 weiter<br />

7 >>> print lis,"zwei",4,; print "weiter"<br />

8 [1, 2, 3] zwei 4 weiter<br />

9 >>> print "%s %s" % ("Hallo", "Welt")<br />

10 Hallo Welt<br />

11 >>> print(lis)<br />

12 [1, 2, 3]<br />

1 >>> import sys<br />

2 >>> sys.stdout.write("Hallo Welt\n")<br />

3 Hallo Welt<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 135 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Zeichenkette, Strings – Darstellung<br />

Syntax<br />

• Einfache oder doppelte<br />

Anführungszeichen<br />

• Nicht limitierendes Anführungszeichen<br />

nutzbar<br />

• Alternativ Escape-Zeichen verwenden<br />

Backslash \<br />

1 >>> "hallo"<br />

2 ’hallo’<br />

3 >>> ’hallo’<br />

4 ’hallo’<br />

1 >>> "spam’s"<br />

2 "spam’s"<br />

3 >>> ’spam"s’<br />

4 ’spam"s’<br />

5 >>> ’spam\’s’<br />

6 "spam’s"<br />

Mehrzeilige Strings<br />

• Drei Anführungszeichen am Anfang<br />

und am Ende<br />

• Zeilenendezeichen als \n verfügbar<br />

• Alle Anführungszeichen verwendbar<br />

1 >>> """hallo<br />

2 ... du "tolle"<br />

3 ... ’perfekte’ Welt """<br />

4 ’hallo\n du "tolle"\n<br />

\’perfekte\’ Welt ’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 136 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Strings – Operationen<br />

Alle üblichen Operationen vorhanden<br />

+ Konkatenation<br />

* Wiederholung<br />

[+i] Indizierung<br />

positive Zahl, 0 ist erstes Zeichen<br />

[-i] Indizierung von hinten<br />

negative Zahl, -1 ist letztes Zeichen<br />

• Slicing<br />

[von:bis] Ausschnitt von inklusive, bis exklusive<br />

[von:] Ausschnitt bis Ende<br />

[:bis] Ausschnitt ab Anfang<br />

[:] Gesamt (Kopie)<br />

1 >>> "Hallo" + " Welt"<br />

2 ’Hallo Welt’<br />

3 >>> "Hallo"*3<br />

4 ’HalloHalloHallo’<br />

5 >>> "Hallo"[0]<br />

6 ’H’<br />

7 >>> "Hallo"[-1]<br />

8 ’o’<br />

1 >>> "Hallo"[1:3]<br />

2 ’al’<br />

3 >>> "Hallo"[1:]<br />

4 ’allo’<br />

5 >>> "Hallo"[:-1]<br />

6 ’Hall’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 137 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Slicing<br />

"SLICEOFSPAM"[von:bis]<br />

• von, einschließend<br />

• bis, ausschließend<br />

Vorzeichen<br />

• Positive Zahlen, von links, ab 0<br />

• Negative Zahlen, von rechts, ab -1<br />

Dritter Parameter Schrittweite<br />

• "SLICEOFSPAM"[von:bis:step]<br />

• Schrittweite, normalerweise 1<br />

Geht auch mit Listen (später)<br />

0 1 2 3 4 5 6 7 8 9 10<br />

s l i c e o f s p a m<br />

-11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1<br />

1 >>> "sliceofspam"[2:-1]<br />

2 ’iceofspa’<br />

3 >>> "sliceofspam"[5:]<br />

4 ’ofspam’<br />

5 >>> "sliceofspam"[:5]<br />

6 ’slice’<br />

7 >>> "sliceofspam"[2:5]<br />

8 ’ice’<br />

1 >>> "sliceofspam"[2:-1:3]<br />

2 ’iop’<br />

3 >>> "sliceofspam"[::4]<br />

4 ’sep’<br />

5 >>> lis = [0,1,2,3,4,5,6,7]<br />

6 >>> lis[::2], lis[1::2]<br />

7 ([0, 2, 4, 6], [1, 3, 5, 7])<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 138 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Strings – Formatierung und Builtins<br />

Formatierung<br />

• Formatstring und Argumente<br />

• Ähnlich zu C, printf<br />

• %s String<br />

• %d Zahl<br />

• %x Hexadezimal<br />

• %e, %f, %g Gleitkommaformate<br />

• %% Prozentzeichen<br />

Benamtes Argument<br />

• %()<br />

• Durch bestimmter Wert in<br />

Abbildung als Argument<br />

• Gefolgt von Argumenttyp<br />

1 >>> "ein %s Papagei" % "toter"<br />

2 ’ein toter Papagei’<br />

3 >>> "%d %s Papageie" % (2, "tote")<br />

4 ’2 tote Papageie’<br />

5 >>> "%x" % 42<br />

6 ’2a’<br />

7 >>> "%X" % 42<br />

8 ’2A’<br />

9 >>> "%e %f %g" % (1.1, 1.2, 1.3)<br />

10 ’1.100000e+00 1.200000 1.3’<br />

11 >>> "%%%s%%" % "hallo"<br />

12 ’%hallo%’<br />

1 >>> "%(name)s heisst %(name)s" %<br />

2 {"name": "Eric"}<br />

3 ’Eric heisst Eric’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 139 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Strings – Builtins und raw Strings<br />

Eingebaute Funktionen, Builtins<br />

• Länge mit len<br />

• Standardoperationen für Vergleich<br />

• Test auf Enthaltensein mit in<br />

raw Strings<br />

• Steuerzeichen quotieren<br />

• Hilfreich bei regulären Ausdrücken,<br />

später<br />

1 >>> len("Hallo")<br />

2 5<br />

3 >>> "hallo" < "wallo"<br />

4 True<br />

5 >>> "al" in "Hallo"<br />

6 True<br />

1 >>> r"raw \n string"<br />

2 ’raw \\n string’<br />

3 >>> print r"raw \n string"<br />

4 raw \n string<br />

5 >>> "normaler \n string"<br />

6 ’normaler \n string’<br />

7 >>> print "normaler \n string"<br />

8 normaler<br />

9 string<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 140 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Strings – weitere Features<br />

string-Modul<br />

• als Modul “importieren”<br />

• Funktionen oder String-Methoden<br />

• Groß- und Kleinschreibung<br />

• Suchen, finden, ersetzen<br />

• Konvertieren, splitten, kleben<br />

• Konkatenation automatisch<br />

• Leerzeichen entfernen<br />

Kommandozeilenargumente<br />

• Modul sys<br />

• Liste von Argumente sys.argv<br />

$ python argv.py a b c d<br />

[’argv.py’, ’a’, ’b’, ’c’, ’d’]<br />

1 >>> import string<br />

2 >>> "ab".upper(), string.upper("ab")<br />

3 (’AB’, ’AB’)<br />

4 >>> string.find("spammify", "mm")<br />

5 3<br />

6 >>> string.atoi("42") # int("42") besser<br />

7 42<br />

8 >>> string.split("spammify"), "mm")<br />

9 [’spa’, ’ify’]<br />

10 >>> "XX".join(["spa", "ify"])<br />

11 ’spaXXify’<br />

12 >>> "spa" "XX" "ify"<br />

13 ’spaXXify’<br />

14 >>> string.strip(" Meaning of Life ")<br />

15 ’Meaning of Life’<br />

1 #!/usr/bin/python<br />

2 import sys<br />

3 print sys.argv<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 141 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Strings<br />

Eigenschaften von Strings<br />

Strings sind unveränderlich<br />

• Operation mit Strings (+, [], etc.)<br />

erzeugen immer neue Strings<br />

• Vorhandene Strings werden niemals<br />

verändert<br />

Strings sind Sequenzen<br />

• Geordnet, die Position der Elemente<br />

ist wichtig<br />

• Klare Menge von unterstützten<br />

Operationen<br />

• Sequenz von Zeichen<br />

Unicode Strings<br />

• u vor dem String<br />

• Typ unicode, nicht str<br />

1 >>> s = "hallo"<br />

2 >>> s[0] = "H"<br />

3 Traceback (most recent call last):<br />

4 File "", line 1, in <br />

5 TypeError: ’str’ object does not<br />

6 support item assignment<br />

1 >>> s = u"hallo"<br />

2 >>> s<br />

3 u’hallo’<br />

4 >>> s == "hallo"<br />

5 True<br />

6 >>> type("hallo"), type(u"hallo")<br />

7 (, )<br />

8 >>> u"hallo" == "hallo"<br />

9 True<br />

>>> "hällo" == u"hällo"<br />

__main__:1: UnicodeWarning: Unicode<br />

equal comparison failed...<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 142 / 326


<strong>Programmieren</strong> in Python<br />

Datentypen, Typhierarchie<br />

Typhierarchie eingebauter Typen<br />

object als Wurzel für alle Typen<br />

isinstance zum Testen<br />

1 >>> isinstance(3, int)<br />

2 True<br />

3 >>> isinstance(3, object)<br />

4 True<br />

object<br />

Ganze<br />

Zahlen<br />

Zahlen<br />

float<br />

Kollektionen<br />

Sequenzen Mengen Abbildungen<br />

unveränderlich veränderlich set dict<br />

int<br />

complex<br />

str<br />

list<br />

long<br />

fractions.<br />

Fraction<br />

unicode<br />

tuple<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 143 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen<br />

Kollektionen<br />

Eingebaute Kollektionen<br />

• Eingebaute Typen zum Verwalten von mehreren Objekten<br />

• Teil der Sprache, nicht nur der Bibliothek<br />

Vorteile<br />

• Effiziente Implementierung<br />

• Einfache Formulierung<br />

• Konzentration aufs Problem<br />

nicht auf technische<br />

Implementierungsdetails<br />

Umfangreich<br />

• Alles was man braucht<br />

• Ungefähr java.util.*<br />

• Strings, Listen, Tupel,<br />

Mengen, Wörterbücher<br />

object<br />

Kollektionen<br />

Sequenzen Mengen Abbildungen<br />

unveränderlich<br />

str<br />

unicode<br />

tuple<br />

veränderlich<br />

list<br />

set<br />

dict<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 144 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Tupel<br />

Tupel – Sequenz<br />

Tupel sind eine Sequenz<br />

• Syntax n-Tupel, n≥ 2 wie erwartet<br />

• 1-Tupel hat spezielle Syntax<br />

(1) wäre nur ein arithmetischer<br />

Ausdruck mit Klammerung<br />

• Leeres Tupel wie erwartet<br />

Beliebig kombinierbar<br />

• Beliebige Typen, schachtelbar<br />

Indizierung<br />

• mit []<br />

• Slicing (wie mit allen Sequenzen)<br />

Ergebnis ist wieder Tupel<br />

1 >>> (1, 2)<br />

2 (1, 2)<br />

3 >>> (1, 1, 1)<br />

4 (1, 1, 1)<br />

5 >>> (1, )<br />

6 (1,)<br />

7 >>> (1)<br />

8 1<br />

9 >>> ()<br />

10 ()<br />

11 >>> (1, "eins", 2.0, (34, 4))<br />

12 (1, ’eins’, 2.0, (34, 4))<br />

13 >>> tup = (1, "zwei", (3, 4))<br />

14 >>> tup[0]<br />

15 1<br />

16 >>> tup[2][1]<br />

17 4<br />

18 >>> tup[1:]<br />

19 (’zwei’, (3, 4))<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 145 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Tupel<br />

Tupel – Builtins<br />

Builtins von Sequenzen<br />

• Länge mit len<br />

• Konkatenation mit +<br />

• Wiederholung mit *<br />

• Test auf Enthaltensein mit in<br />

Automatisch Tupel<br />

• Auch ohne Klammern<br />

Tupelzuweisung<br />

• Nette Syntax<br />

• Geht auch ohne Klammern<br />

• Gut bei Rückgabewerten<br />

1 >>> tup = (1, "zwei", (3, 4))<br />

2 >>> len(tup)<br />

3 3<br />

4 >>> tup + tup<br />

5 (1, ’zwei’, (3, 4), 1, ’zwei’, (3, 4))<br />

6 >>> tup*2<br />

7 (1, ’zwei’, (3, 4), 1, ’zwei’, (3, 4))<br />

8 >>> (3, 4) in tup<br />

9 True<br />

1 >>> 1, 2<br />

2 (1, 2)<br />

3 >>> (1, 2)<br />

4 (1, 2)<br />

5 >>> (a, b) = (1, 2)<br />

6 >>> print a, b<br />

7 1 2<br />

8 >>> b, a = a, b<br />

9 >>> a, b<br />

10 (2, 1)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 146 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Tupel<br />

Tupel – Unveränderliche Sequenz<br />

Tupel sind unveränderlich<br />

• Operationen mit Tupel erzeugen<br />

neue Tupel<br />

• Achtung! Tupel kann veränderliche<br />

Werte als Tupelelemente haben<br />

Tupel sind Sequenzen<br />

• Geordnet<br />

• Klare Menge unterstützter<br />

Operationen<br />

• Sequenz von Werten beliebigen Typs<br />

im Gegensatz zu Strings (nur Zeichen)<br />

1 >>> tup = (1,2,3)<br />

2 >>> tup[1] = "zwei"<br />

3 Traceback (most recent call last):<br />

4 File "", line 1, in <br />

5 TypeError: ’tuple’ object does not<br />

6 support item assignment<br />

7 >>> tup = (1, [], 3)<br />

8 >>> tup[1].append("zwei")<br />

9 >>> tup<br />

10 (1, [’zwei’], 3)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 147 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Listen<br />

Listen – Sequenz<br />

Syntax wie Tupel<br />

• Umschlossen mit [ und ]<br />

• Keine spezielle Syntax mehr für<br />

einelementige Listen<br />

• Leere Liste mit []<br />

Beliebig kombinierbar und schachtelbar<br />

• Auch mit Tupel<br />

Sonst wie Tupel<br />

1 >>> [1, 2, 3]<br />

2 [1, 2, 3]<br />

3 >>> [1], []<br />

4 [1], []<br />

5 >>> [1, [2, "zwei"], (3, "drei")]<br />

6 [1, [2, ’zwei’], (3, ’drei’)]<br />

7 >>> lis = [1, [2, "zwei"], (3, "drei")]<br />

8 >>> lis[0]<br />

9 1<br />

10 >>> lis[1:]<br />

11 [[2, ’zwei’], (3, ’drei’)]<br />

12 >>> lis[2][0], len(lis)<br />

13 (3, 3)<br />

14 >>> lis + [4,5]<br />

15 [1, [2, ’zwei’], (3, ’drei’), 4, 5]<br />

16 >>> 1 in lis<br />

17 True<br />

18 >>> (lis*2)[1:-2]<br />

19 [[2, ’zwei’], (3, ’drei’), 1]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 148 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Listen<br />

Listen – Veränderliche Sequenz<br />

Ändern<br />

• Zuweisung von Teilen<br />

• Löschen<br />

Kopien und Zuweisung<br />

• Operationen erzeugen Kopien<br />

• Nachträgliches Verändern der<br />

Parameter ohne Einfluss<br />

Flache Kopien<br />

• Kopien nur auf oberster Ebene<br />

• Erzeugen neuer Listenstruktur<br />

• Die Elemente werden nicht kopiert,<br />

sondern nur Referenzen<br />

• Ändern der Elemente ist sichtbar<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> lis[0] = "eins"<br />

3 >>> lis<br />

4 [’eins’, 2, 3]<br />

5 >>> del lis[0]<br />

6 >>> lis<br />

7 [2, 3]<br />

1 >>> lis, kat = ["a", "b"], ["c", "d"]<br />

2 >>> lk = lis + kat<br />

3 >>> lk<br />

4 [’a’, ’b’, ’c’, ’d’]<br />

5 >>> lis[0] = "X"<br />

6 >>> lis, lk<br />

7 ([’X’, ’b’], [’a’, ’b’, ’c’, ’d’])<br />

8 >>> tup = (lis, kat)<br />

9 >>> tup<br />

10 ([’X’, ’b’], [’c’, ’d’])<br />

11 >>> lis[1] = "Y"<br />

12 >>> tup<br />

13 ([’X’, ’Y’], [’c’, ’d’])<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 149 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Listen<br />

Listen – Zuweisungen<br />

Zuweisungskompatibilität<br />

• Sequenzen sind untereinander<br />

zuweisungskompatibel<br />

Slice-Zuweisung möglich<br />

• Der Bereich wird durch Sequenz als<br />

Liste ersetzt<br />

Destruktive Methoden<br />

• append und extend ändern gegebene<br />

Liste, kein Rückgabewert<br />

• del ändert Liste<br />

• Zuweisung an Index ändert Liste<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> lis[1:2] = ("zwei", "two")<br />

3 >>> lis<br />

4 [1, ’zwei’, ’two’, 3]<br />

5 >>> lis[1:2] = ["zwei", "two"]<br />

6 >>> lis<br />

7 [1, ’zwei’, ’two’, ’two’, 3]<br />

8 >>> lis.append(4)<br />

9 >>> lis<br />

10 [1, ’zwei’, ’two’, ’two’, 3, 4]<br />

11 >>> lis.extend([5, 6])<br />

12 >>> lis<br />

13 [1, ’zwei’, ’two’, ’two’, 3, 4, 5, 6]<br />

14 >>> del lis[1:3]<br />

15 >>> lis<br />

16 [1, ’two’, 3, 4, 5, 6]<br />

17 >>> lis[1] = 2<br />

18 >>> lis<br />

19 [1, 2, 3, 4, 5, 6]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 150 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Listen<br />

Listen – Weitere Methoden<br />

range generiert Zahlenliste<br />

• Anfang, erstes Argument, optional<br />

(default 0)<br />

• Ende, zweites Argument<br />

• Schrittweite, drittes Argument, optional<br />

(default 1)<br />

Weitere destruktive Methoden<br />

• pop, insert<br />

Kellerverhalten und mehr<br />

• reverse, sort, sorted<br />

klassische Listenoperationen<br />

1 >>> lis = [4, 3, 2.5, 2, 1, 0, -1]<br />

2 >>> sorted(lis)<br />

3 [-1, 0, 1, 2, 2.5, 3, 4]<br />

4 >>> lis.sort(); lis<br />

5 [-1, 0, 1, 2, 2.5, 3, 4]<br />

1 >>> range(5)<br />

2 [0, 1, 2, 3, 4]<br />

3 >>> range(1, 5)<br />

4 [1, 2, 3, 4]<br />

5 >>> range(0, 50, 10)<br />

6 [0, 10, 20, 30, 40]<br />

7 >>> lis = range(5)<br />

8 >>> lis.append(5); lis<br />

9 [0, 1, 2, 3, 4, 5]<br />

10 >>> lis.pop()<br />

11 5<br />

12 >>> lis<br />

13 [0, 1, 2, 3, 4]<br />

14 >>> lis.insert(0, -1); lis<br />

15 [-1, 0, 1, 2, 3, 4]<br />

16 >>> lis.insert(4, 2.5); lis<br />

17 [-1, 0, 1, 2, 2.5, 3, 4]<br />

18 >>> lis.reverse(); lis<br />

19 [4, 3, 2.5, 2, 1, 0, -1]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 151 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Listen<br />

Listen – Eine weitere Sequenz, veränderlich<br />

Listen sind veränderlich<br />

• Sequenz-Operationen<br />

unveränderlicher Operationen mit<br />

Listen erzeugen neue Listen auf<br />

oberster Ebene<br />

• Spezielle destruktive<br />

Listen-Operationen, ohne Wert<br />

Listen sind Sequenzen<br />

• Ähnlich zu Feld (ArrayList) in Java<br />

• Laufzeitverhalten ähnlich zu Feld<br />

Warum Listen und Tupel?<br />

• Bei gemischten Typen eher Tupel;<br />

bei Liste möglich, nicht intuitiv<br />

• Unveränderliches Tupel effizienter<br />

• Tupel kann als Schlüssel im<br />

Wörterbuch genutzt werden<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> lis[1] = "zwei"<br />

3 >>> lis<br />

4 [1, ’zwei’, 3]<br />

5 >>> lis.append(4)<br />

6 >>> lis<br />

7 [1, ’zwei’, 3, 4]<br />

1 >>> (1, "ab")<br />

2 (1, ’ab’)<br />

3 >>> [1, "ab"]<br />

4 [1, ’ab’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 152 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Wörterbücher<br />

Dictionaries, Wörterbücher<br />

Dictionary, Wörterbuch<br />

• Abbildung unveränderlicher Werte<br />

(Schlüssel) auf beliebigen Werten<br />

• Syntax für Zugriff und Zuweisung wie<br />

beim Feld<br />

• Realisiert über Hashing<br />

Vorteile<br />

• Verwendung einfach und intuitiv<br />

11<br />

• Schlüssel nicht beschränkt auf Zahlen >>> dic.keys()<br />

12 [’eggs’, ’spam’]<br />

• Keine Feldgröße notwendig<br />

13 >>> dic.values()<br />

Dictionaries und Sequenzen<br />

14 [42, 3]<br />

• Schlüsselmenge (Sequenz),<br />

Wertemenge und Tupelmenge<br />

Schlüssel/Wert erzeugbar<br />

• Test auf Enthaltensein gegen<br />

Schlüsselmenge<br />

1 >>> dic = {}<br />

2 >>> dic = { ’spam’ : 2 }<br />

3 >>> dic[’spam’]<br />

4 2<br />

5 >>> dic[’spam’] = 3<br />

6 >>> dic<br />

7 {’spam’: 3}<br />

8 >>> dic[’eggs’] = 42<br />

9 >>> dic<br />

10 {’eggs’: 42, ’spam’: 3}<br />

15 >>> dic.items()<br />

16 [(’eggs’, 42), (’spam’, 3)]<br />

17 >>> ’eggs’ in dic<br />

18 True<br />

19 >>> dic.has_key(’spam’)<br />

20 True<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 153 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Wörterbücher<br />

Dictionaries – Builtins und Schlüsseleigenschaften<br />

Eingebaute Funktionen<br />

• len für Anzahl Schlüssel<br />

• del zum Löschen<br />

• Keine Slicing-Operationen<br />

Dictionary ist keine Sequenz<br />

Schlüssel unveränderlich<br />

• Intern mit Hashing realisiert<br />

• Zahlen, Strings, etc.<br />

• Tupel (auch tiefe Strukturen) sind<br />

erlaubt<br />

Ausnahme bei nicht vorhandenem<br />

Schlüssel<br />

1 >>> dic = {’eggs’: 42, ’spam’: 3}<br />

2 >>> len(dic)<br />

3 2<br />

4 >>> del dic[’eggs’]; dic<br />

5 {’spam’: 3}<br />

6 >>> dic[0:]<br />

7 Traceback (most recent call last):<br />

8 File "", line 1, in <br />

9 TypeError: unhashable type<br />

10 >>> dic[(1,2)] = ’tupel’<br />

11 >>> dic<br />

12 {(1, 2): ’tupel’, ’spam’: 3}<br />

13 >>> dic[[1,2]] = ’liste’<br />

14 Traceback (most recent call last):<br />

15 File "", line 1, in <br />

16 TypeError: unhashable type: ’list’<br />

17 >>> dic[’cheese’]<br />

18 Traceback (most recent call last):<br />

19 File "", line 1, in <br />

20 KeyError: ’cheese’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 154 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Wörterbücher<br />

Dictionaries – Veränderliche Abbildungen<br />

Dictionaries sind veränderlich<br />

• Zuweisung mit neuem Schlüssel fügt neue Elemente hinzu<br />

• Zuweisung mit existierendem Schlüssel überschreibt Wert<br />

• del löscht Schlüssel/Wert Zuordnung<br />

Dictionaries sind die einzigen Abbildungen<br />

• Ungeordnet (keine Sequenz), Zugriff nur über Schlüssel<br />

• Feste Menge von unterstützten Operationen<br />

• Zugriff zu beliebigen Objekten beliebigen Typs (Werte)<br />

• Zugriff über beliebige unveränderliche Objekte (Schlüssel)<br />

• Unveränderlicher Schlüssel<br />

• Wegen interner Implementierung mit Hashing<br />

• Sonst würde man Wert nicht wiederfinden<br />

• Siehe Algorithmen und Datenstrukturen<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 155 / 326


<strong>Programmieren</strong> in Python<br />

Kollektionen, Mengen<br />

Mengen – Veränderlich, keine Reihenfolge<br />

Mengen<br />

• Keine doppelten Elemente<br />

• Keine Reihenfolge, keine Sequenz<br />

• Realisiert wie Dictionaries,<br />

nur ist der Wert egal<br />

Eingebaute Funktionen und Operationen<br />

• len für Anzahl Elemente<br />

• in für Test auf Enthaltensein<br />

• Mengenoperationen mit | und &<br />

1 >>> s = set()<br />

2 >>> s.add(1)<br />

3 >>> s<br />

4 set([1])<br />

5 >>> s.add(2); s.add(3)<br />

6 >>> s<br />

7 set([1, 2, 3])<br />

8 >>> s.add(2)<br />

9 >>> s<br />

10 set([1, 2, 3])<br />

11 >>> 2 in s<br />

12 True<br />

13 >>> 4 in s<br />

14 False<br />

15 >>> len(s)<br />

16 3<br />

17 >>> s | set([2,3,4])<br />

18 set([1, 2, 3, 4])<br />

19 >>> s & set([2,3,4])<br />

20 set([2, 3])<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 156 / 326


<strong>Programmieren</strong> in Python<br />

Dateien<br />

Dateien<br />

Modul os für Systemoperationen<br />

• chdir um Verzeichnis zu wechseln<br />

• getcwd um Verzeichnis anzuzeigen<br />

• Unix und Windows Notation<br />

Dateien<br />

•<br />

8<br />

file ist eigener Datentyp<br />

938848<br />

9 >>> inhalt[700539:700600]<br />

• Konstruktor mit Dateiname und<br />

10 "python\npython’s\npythons\npyx\npyx’s<br />

Bearbeitungsart (r lesen, w schreiben,<br />

11 \npyxes\nq\nqua\nquack\nquack’s\nq"<br />

a erweitern)<br />

12 >>> eingabe.close()<br />

• read zum Lesen der gesamten! Datei<br />

• readlines für String-Liste der Zeilen<br />

• close Schließen optional, über<br />

Garbage Collector<br />

• Schreiben funktioniert ähnlich<br />

1 >>> import os<br />

2 >>> os.chdir(’/usr/share/dict’)<br />

3 >>> os.getcwd()<br />

4 ’/usr/share/dict’<br />

5 >>> eingabe = file("words", "r")<br />

6 >>> inhalt = eingabe.read()<br />

7 >>> len(inhalt)<br />

13 >>> os.chdir(’/tmp’)<br />

14 >>> ausgabe = file(’wordskopie’, ’w’)<br />

15 >>> ausgabe.write(inhalt)<br />

16 >>> ausgabe.close()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 157 / 326


<strong>Programmieren</strong> in Python<br />

Typen<br />

Typ-Überprüfung und Konversion<br />

Test welcher Typ<br />

• type gibt Typ zurück<br />

• isinstance testet ob von Typ<br />

• Vergleich und Auswahl von Typen<br />

Typkonvertierung<br />

• Typname als Funktionsaufruf<br />

Typen<br />

• int, long, float, complex<br />

• str, list, tuple<br />

• dict, . . .<br />

Konversion von/zu Zeichen<br />

• Zeichen in Python keine Zahl,<br />

nicht vorhanden<br />

• ord und chr<br />

1 >>> type([])<br />

2 <br />

3 >>> lis = [1,2,3]; type(lis)<br />

4 <br />

5 >>> type(lis)==list, type(lis)==type({})<br />

6 True, False<br />

7 >>> isinstance(lis, list)<br />

8 True<br />

9 >>> int, long, float, complex<br />

10 (, ,<br />

11 , )<br />

12 >>> str, list, tuple, dict<br />

13 (, ,<br />

14 , )<br />

15 >>> int("12")<br />

16 12<br />

17 >>> list("123")<br />

18 [’1’, ’2’, ’3’]<br />

19 >>> ord(’A’), chr(65)<br />

20 (65, ’A’)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 158 / 326


<strong>Programmieren</strong> in Python<br />

Typen<br />

Die Doku ist Dein Freund<br />

Dokumentation<br />

• docs.python.org<br />

• Tutorial, sehr guter Einstieg<br />

• Bibliothek, die Referenz für<br />

alle eingebauten und<br />

anderen Objekte,<br />

Funktionen, Module<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 159 / 326


<strong>Programmieren</strong> in Python<br />

Variablen<br />

Variablen<br />

Verwendung<br />

• Müssen nicht deklariert werden<br />

• Müssen vor erster Verwendung<br />

initialisiert werden<br />

Typ, dynamisch und streng<br />

• Dynamische Typisierung, Variable an<br />

alles bindbar<br />

• Strenge Typisierung, Gebundenes<br />

Objekt hat Typ<br />

Syntaxspezialitäten<br />

• Zuweisung hat keinen Wert<br />

• Mehrfachzuweisung möglich<br />

• Tupelzuweisung<br />

Gültige Variablenbezeichner wie in Java,<br />

keine Schlüsselwörter<br />

1 >>> x = 3<br />

2 >>> x<br />

3 3<br />

4 >>> y<br />

5 NameError: name ’y’ is not defined<br />

6 >>> x = 3<br />

7 >>> x = "Hallo"<br />

8 >>> x = 3; x + 3<br />

9 6<br />

10 >>> x = "3"; x + 3<br />

11 TypeError: cannot concatenate<br />

12 ’str’ and ’int’ objects<br />

1 >>> x = y = 3<br />

2 >>> x, y = 3, 4<br />

3 >>> x, y<br />

4 (3, 4)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 160 / 326


<strong>Programmieren</strong> in Python<br />

Variablen<br />

Zuweisung und Ausdrücke<br />

Gleichheit und Identität<br />

• Alles ist ein Objekt<br />

• Gleichheit ==, Objektidentität is<br />

Zuweisung<br />

• Variablen sind Namen, die an Objekte<br />

gebunden sind<br />

• Rechte Seite einer Zuweisung gibt<br />

Objekt (vorhandenes oder neues)<br />

9<br />

10<br />

[1, 2, 3]<br />

>>> lis = [1, 2, 3]<br />

zurück<br />

11 >>> kat = lis[:] # Kopie<br />

12 >>> lis == kat, lis is kat<br />

• Linke Seite einer Zuweisungen ist eine13 (True, False)<br />

Name an den Objekt gebunden wird<br />

Ausdrücke evaluieren zu neuen Objekten<br />

• Die Sequenz von Anfang bis Ende ist<br />

ein Ausdruck<br />

• [:] macht eine (flache) Kopie<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> kat = [1, 2, 3]<br />

3 >>> lis == kat, lis is kat<br />

4 (True, False)<br />

5 >>> lis.append(4)<br />

6 >>> lis<br />

7 [1, 2, 3, 4]<br />

8 >>> kat<br />

lis<br />

kat<br />

1 2 3<br />

1 2 3<br />

4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 161 / 326


<strong>Programmieren</strong> in Python<br />

Variablen<br />

Referenzsemantik<br />

Referenzsemantik<br />

• Variablen sind Namen, die an Objekte<br />

gebunden sind<br />

• Rechte Seite einer Zuweisung gibt<br />

Objekt (vorhandenes oder neues)<br />

zurück<br />

• Linke Seite einer Zuweisungen ist eine<br />

Name an den Objekt gebunden wird<br />

Namen evaluieren zu dem gebundenem<br />

Objekt<br />

• Änderungen von Objekten über alle<br />

Referenzen sichtbar<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> kat = lis<br />

3 >>> lis == kat, lis is kat<br />

4 (True, True)<br />

5 >>> lis.append(4)<br />

6 >>> lis<br />

7 [1, 2, 3, 4]<br />

8 >>> kat<br />

9 [1, 2, 3, 4]<br />

lis<br />

kat<br />

1 2 3<br />

4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 162 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Kontrollstrukturen – Verzweigung<br />

Verzweigung<br />

• Schlüsselwörter: if, elif, else<br />

• : Ausdruck, der als<br />

Wahrheitswert interpretiert wird<br />

• : Beliebige Folge von<br />

Anweisungen<br />

Syntax<br />

• Bedingung endet mit Doppelpunkt,<br />

Keine Klammern notwendig<br />

• ACHTUNG! Einrückung ist signifikant<br />

und Teil der Syntax<br />

• Block durch Einrücktiefe bestimmt<br />

• Einrückung Tabulator oder gleiche<br />

Anzahl an Leerzeichen<br />

• Keine (geschweiften) Klammern!<br />

Einzeiler möglich, vermeiden<br />

if :<br />

<br />

[elif :<br />

]*<br />

[else:<br />

]<br />

1 if 0 == 0:<br />

2 print "ja"<br />

3 if "nichtleerer String":<br />

4 print "ja"<br />

5 else:<br />

6 print "nein"<br />

7 if 0:<br />

8 print "eins"<br />

9 print "zwei"<br />

10 print "drei"<br />

11 if 1: print "eins"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 163 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

if/else Ausdruck statt ?-Operator<br />

Syntax ungewöhnlich<br />

• Erst Ergebniswert im “normalen”<br />

Fall<br />

• Dann Bedingung<br />

• Dann “alternativer” Fall<br />

Alternative mit booleschem<br />

Ausdruck<br />

• and und or evaluieren nur so<br />

weit wie notwendig<br />

• Nachbau mit and/ormöglich<br />

• Problematisch wenn “normaler”<br />

Wert äquivalent zu falsch ist<br />

• Nicht mehr statt if/else<br />

verwenden<br />

if else <br />

// in Java, C<br />

? : <br />

1 >>> x, y = 1, 2<br />

2 >>> e = "kleiner" if x>> e<br />

4 ’kleiner’<br />

and or <br />

1 >>> x, y = 1, 2<br />

2 >>> e = x>> e<br />

4 ’kleiner’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 164 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Kontrollstrukturen – while-Schleife<br />

while-Schleife<br />

• Schlüsselwörter: while, else, break,<br />

continue, pass<br />

• else-Zweig nur, wenn Schleife ohne<br />

break verlassen wurde<br />

• pass, leere Anweisung, macht nichts,<br />

Ersatz für {}<br />

Syntax<br />

• Wieder Einrücken als integraler<br />

Bestandteil der Schleifensyntax<br />

while :<br />

<br />

[else:<br />

]<br />

1 lis = [1, 2, 3, 4]<br />

2 while lis:<br />

3 print lis.pop()<br />

4 else:<br />

5 print "Ende"<br />

4<br />

3<br />

2<br />

1<br />

Ende<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 165 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Kontrollstrukturen – for-Schleife<br />

for-Schleife<br />

• Schlüsselwörter: for, in, break,<br />

continue, pass<br />

• Iterieren über Elemente in Sequenzen<br />

• in wählt Elemente aus Sequenz<br />

sukzessive aus und weist sie je<br />

Durchlauf der Variable zu<br />

• Klassische Schleife über Indexe nur<br />

nach als Nachbau mit range<br />

range<br />

• range(von, bis, step)<br />

• Erzeugt eine Liste von Zahlen von<br />

inklusive, bis exklusive<br />

• von optional, default 0<br />

• step optional, default 1<br />

for in :<br />

<br />

[else:<br />

]<br />

1 for ele in ["Hallo", "Welt"]:<br />

2 print ele<br />

3 for idx in range(1, 4):<br />

4 print idx<br />

5 for ch in "Hi":<br />

6 print ch<br />

Hallo<br />

Welt<br />

1<br />

2<br />

3<br />

H<br />

i<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 166 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Kontrollstrukturen – for-Schleife, Dictionaries<br />

for-Schleife und Dictionaries<br />

• Fragt Objekte, ob sie auch eine<br />

Sequenz sein können<br />

• Das Dictionary sagt, ja, dann bin ich<br />

eine Sequenz der Schlüssel<br />

• Dann wird über die Schlüssel iteriert<br />

Auch nett mit items und Tupelzuweisung<br />

1 dic = { 1: ’eins’, 2: ’zwei’ }<br />

2 for key in dic: # wie dic.keys()<br />

3 print key, dic[key]<br />

1 eins<br />

2 zwei<br />

1 dic = { 1: ’eins’, 2: ’zwei’ }<br />

2 print dic.items()<br />

3 for key, value in dic.items():<br />

4 print key, value<br />

[(1, ’eins’), (2, ’zwei’)]<br />

1 eins<br />

2 zwei<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 167 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Kontrollstrukturen – for-Schleife, typischer Einsatz<br />

Klassische for-Schleife<br />

• Durchlaufen von Index-Werten<br />

• Sequenz von Index-Werten, mit range<br />

erzeugt<br />

• Selten benötigt<br />

• Java/C Idiom, weniger Python<br />

Feldzugriff vermeiden<br />

• Keine expliziten Indexvariablen<br />

• Eleganter<br />

• Kein Indexfehler möglich!<br />

• Funktioniert für alle Sequenzen<br />

1 for idx in range(100): # 0-99 in Python<br />

2 print idx<br />

1 // 0-99 in Java<br />

2 for(int i=0; i < 100; i+=1) {<br />

3 System.out.println(idx);<br />

4 }<br />

1 for ele in arr: # Feldzugriff in Python<br />

2 print ele<br />

1 // Feldzugriff in Java<br />

2 for(int i=0; i < arr.length; i+=1) {<br />

3 System.out.println(arr[i]);<br />

4 }<br />

1 for e in (0, 1, 2, 3): # alle Sequenzen<br />

2 print e<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 168 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Schleifenbeispiel – Dateiinhalte durchlaufen<br />

Dateien mit while<br />

• Endlosschleife mit break<br />

• Einlesen bis Fehlschlag<br />

• Schließen optional, aber guter Stil<br />

Dateien mit for<br />

• Eleganter<br />

• Alles Einlesen in eine Liste<br />

Noch Eleganter<br />

• Default Datei-Aktion ist lesen<br />

• Default ist zeilenweise einlesen<br />

• Automatisch schließen, da offene<br />

Datei nicht gebunden<br />

1 # C-Style :-(<br />

2 eingabe = file("dat.txt", "r")<br />

3 while True:<br />

4 line = eingabe.readline()<br />

5 if not line:<br />

6 break<br />

7 print line<br />

8 eingabe.close()<br />

1 # Besser :-|<br />

2 eingabe = file("dat.txt", "r")<br />

3 for line in eingabe.readlines():<br />

4 print line<br />

5 eingabe.close()<br />

1 # Python-Style :-)<br />

2 for line in file("dat.txt"):<br />

3 print line<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 169 / 326


<strong>Programmieren</strong> in Python<br />

Kontrollstrukturen<br />

Hinweise zu Kontrollstrukturen<br />

Beim Editieren<br />

• Vergessen Sie die Doppelpunkte nicht<br />

• Beginnen Sie immer in der ersten Spalte<br />

• Rücken Sie konsistent ein (nur Leerzeichen oder nur Tabulatoren)<br />

• Rücken Sie immer gleich weit ein (4 Zeichen)<br />

• Oder am besten alles mit der IDLE<br />

Leerzeilen beenden im interaktiven Modus einen Anweisungsblock<br />

Erwarten Sie nicht immer ein Ergebnis<br />

• Beispiel: append<br />

Schreiben Sie nicht Java/C in Python!<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 170 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Funktionen<br />

Definition mit def<br />

• Erstellt Funktionsobjekt und bindet<br />

Namen daran<br />

• return für Rückgabe, ansonsten<br />

automatisch None<br />

• Eins oder mehrere<br />

Argumente/Parameter werden<br />

per Namensbindung übergeben<br />

def ([ [, ...]]):<br />

[]<br />

<br />

[return ]<br />

1 def mult(x, y):<br />

2 "Multipliziere zwei Objekte x, y"<br />

3 return x*y<br />

• Dokumentationsstring <br />

eingebaut, optionale erste Zeile<br />

Auch interaktiv eingebbar<br />

• Leerzeile zum Beenden<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 171 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Funktionen – Beispiel, intersect<br />

Ziel<br />

• Schnittmenge von Sequenzen<br />

• Abstraktion als Funktion<br />

Lösung<br />

• Python-Funktion intersect<br />

• Ergebnis initial eine leere Sequenz<br />

• Für alle Elemente in erster Sequenz<br />

• Suche dieses Element in zweiter<br />

Sequenz<br />

• Wenn vorhanden, dann ist es ein<br />

gemeinsames Element; füge es zum<br />

Ergebnis hinzu<br />

• Gib Ergebnis zurück<br />

Beispiele<br />

• Strings, Listen, Tupel sind Sequenzen<br />

1 def intersect(seq1, seq2):<br />

2 """Schnittmenge von Sequenzen<br />

3 seq1 und seq2"""<br />

4 res = []<br />

5 for ele in seq1:<br />

6 if ele in seq2:<br />

7 res.append(ele)<br />

8 return res<br />

1 >>> intersect("spam", "scam")<br />

2 [’s’, ’a’, ’m’]<br />

3 >>> intersect([1,2,3], (4,2,6))<br />

4 [2]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 172 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Gültigkeitsbereiche in Funktionen<br />

Funktionsaufrufe sind Namensraum<br />

• Jeder Funktionsaufruf bietet einen<br />

neuen Gültigkeitsbereich<br />

(Namensraum)<br />

• Die Definition auch<br />

Beispiel f, g<br />

• Variable g wird nicht verändert<br />

• Weder bei der Definition<br />

• Noch bei dem Aufruf<br />

• g in der Funktion ist eine neue lokale<br />

Variable<br />

1 >>> g = 1<br />

2 >>> def f(x, y):<br />

3 g=2<br />

4 return x+y<br />

5<br />

6 >>> g<br />

7 1<br />

8 >>> f(5, 6)<br />

9 11<br />

10 >>> g<br />

11 1<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 173 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Gültigkeitsbereiche in Funktionen – Durchgriff<br />

Durchgriff auf globale Variable<br />

• Schlüsselwort global<br />

• Variable vom “globalen” Namensraum<br />

wird verwendet<br />

• Durchgriff immer nur auf äußerste<br />

“globale” Ebene möglich<br />

• Wenn möglich vermeiden*<br />

1 >>> g = 1<br />

2 >>> def f(x, y):<br />

3 global g<br />

4 g=2<br />

5 return x+y<br />

6<br />

7 >>> g<br />

8 1<br />

9 >>> f(5, 6)<br />

10 11<br />

11 >>> g<br />

12 2<br />

*Bei OpenGL muss man dann leider doch mal ab<br />

und zu. . .<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 174 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Gültigkeitsbereiche Funktionen – Überschreiben<br />

Überschreiben Global/lokal Eigenschaft<br />

• Überschreiben der global/lokal<br />

Eigenschaft nicht möglich<br />

• In f1 ist g als Parameter lokal, kann<br />

nicht auch global sein<br />

Nur lesen automatisch möglich<br />

• Direkter Zugriff auf globalen<br />

Namensraum möglich wie in f2<br />

• Syntaktisch ok, stilistisch unschön<br />

Nachträglich global machen<br />

• Wenn vorher nur gelesen wurde, dann<br />

wurde globaler Wert gelesen, f3<br />

• Wenn vorher geschrieben wurde, dann<br />

geht lokaler Wert verloren, f4<br />

• Warnung: unschön, vermeiden<br />

1 >>> def f1(x, g):<br />

2 global g<br />

3 SyntaxError: name ’g’ is local and global<br />

1 >>> g = 1<br />

2 >>> def f2(x, y):<br />

3 return g+1<br />

4 >>> f2(5, 6)<br />

5 2<br />

1 >>> def f3(x):<br />

2 y = g<br />

3 global g<br />

4 SyntaxWarning: name ’g’ is used<br />

5 prior to global declaration<br />

6 >>> def f4(x):<br />

7 g = 3<br />

8 global g<br />

9 SyntaxWarning: name ’g’ is<br />

10 assigned to before global<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 175 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Regeln für Gültigkeitsbereiche<br />

Lokal<br />

• Jeder Funktionsaufruf bietet einen<br />

neuen lokalen Gültigkeitsbereich<br />

(Namensraum)<br />

• Jeder Aufruf, Rekursion funktioniert<br />

• Zugewiesene Namen sind lokal im<br />

aktuellen Gültigskeitsbereich<br />

• können explizit global werden<br />

• Blöcke (Einrückungen) sind kein<br />

eigener Gültigkeitsbereich<br />

Global<br />

• Das einschließende Modul ist ein<br />

globaler Gültigkeitsbereich<br />

• Der interaktive Modus ist ein Modul,<br />

hat den Namen ’__main__’<br />

Reservierte Namen sind Teil der Sprache<br />

Reserviert<br />

Modul<br />

Modul<br />

Funktionsdefinition<br />

Funktionsaufruf<br />

Funktionsaufruf<br />

Funktionsaufruf<br />

Funktionsaufruf<br />

Funktionsdefinition<br />

Funktionsdefinition<br />

Funktionsaufruf<br />

Funktionsaufruf<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 176 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Namensauflösung, LGB-Regel<br />

Namen in drei Bereichen suchen<br />

• Erst Lokal<br />

zum Beispiel Variablen und Parameter<br />

in def<br />

• Dann Global<br />

zum Beispiel Funktionsdefinition,<br />

Variablen auf oberster Ebene<br />

• Dann eingeBaute<br />

builtin, reservierte Namen, zum<br />

Beispiel len, file<br />

Namensbindungen<br />

• In Funktionen lokal<br />

• In Moduln global<br />

• Für reservierte Namen vermeiden<br />

1 >>> a,b = 1,2<br />

2 >>> def f():<br />

3 a = 3<br />

eingeBaut<br />

4 print a,b<br />

5 >>> f()<br />

6 3 2<br />

7 >>> a,b<br />

8 (1, 2)<br />

Global<br />

Lokal<br />

9 >>> list = "kein Typ mehr, vermeiden"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 177 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Parameterübergabe<br />

Parameterübergabe ist Namensbindung<br />

• Parameternamen werden an<br />

übergebene Objekte gebunden<br />

• Neue lokale Namen<br />

• Bindung von Namen an Objekt<br />

beeinflusst Objekt nicht<br />

Verwendung<br />

• Call by Reference<br />

• Das Ändern eines änderbaren Objekts<br />

hat Auswirkungen (Seiteneffekte)<br />

• Bei unveränderlichen Objekten kann<br />

es keine Auswirkungen haben, wie call<br />

by value<br />

1 def aendern(x, y):<br />

2 x = 2<br />

3 y[1] = 1<br />

1 >>> x, y = ([1,2], [3,4])<br />

2 >>> aendern(x, y)<br />

3 >>> x, y<br />

4 ([1, 2], [3, 1])<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 178 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Parameterübergabe – Vorgabewerte<br />

Vorgabewerte (Default)<br />

• Vorgabewert kann optional bei jedem<br />

Parameter angegeben werden<br />

• Zusätzlich = und Ausdruck, der zu<br />

Vorgabewert evaluiert<br />

• Parameter mit Vorgabewerten hinter<br />

die Parameter ohne Vorgabewerte<br />

• Stellungsparameter,<br />

Positionsparameter<br />

Aufruf<br />

• Wert für Parameter mit Vorgabewert<br />

kann weggelassen werden<br />

• Falls Wert weggelassen, wird<br />

Vorgabewert eingesetzt<br />

1 def ink(x, a=1):<br />

2 return x+a<br />

1 >>> ink(3)<br />

2 4<br />

3 >>> ink(3, 1)<br />

4 4<br />

5 >>> ink(3, 17)<br />

6 20<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 179 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Vorgabewerte – Anwendungsbeispiel<br />

Suche von Elementen in Sequenz<br />

• Vorgabewerte für start und ende<br />

des Suchbereichs<br />

• Sinnvolle Vorgabe ist 0 für start<br />

und Länge der Sequenz für ende<br />

Nutzung<br />

• Automatische Belegung von<br />

links nach rechts<br />

• Ergänzung nach Position,<br />

um ende zu übergeben muss<br />

man auch start übergeben<br />

1 def suche(seq, ele, start=0, ende=None):<br />

2 if ende is None:<br />

3 ende = len(seq)<br />

4 for pos in range(start, ende):<br />

5 if seq[pos] == ele:<br />

6 return pos<br />

1 >>> suche([1,2,3,4,5,6], 3)<br />

2 2<br />

3 >>> suche([1,2,3,4,5,6], 3, 0)<br />

4 2<br />

5 >>> suche([1,2,3,4,5,6], 3, 4)<br />

6 >>> suche([1,2,3,4,5,6], 3, 0, 6)<br />

7 2<br />

8 >>> suche([1,2,3,4,5,6], 3, 0, 1)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 180 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Vorgabewerte – Besonderheiten<br />

Gültigkeit<br />

1<br />

2<br />

def suche(seq,ele,start=0,ende=len(seq)):<br />

for pos in range(start, ende):<br />

• Parametername während der<br />

3<br />

Definition der Vorgabewerte noch nicht 4<br />

...<br />

Traceback (most recent call last):<br />

nutzbar<br />

5 File "", line 1, in <br />

• Umgehen durch Markieren mit None<br />

und dynamische Berechnung<br />

Lebenszyklus<br />

• Vorgabewert wird nur einmal<br />

ausgewertet, bei der<br />

Funktionsdefinition<br />

• Überraschungen bei änderbaren<br />

Vorgabewerten<br />

• Änderungen bleiben über Aufrufe<br />

hinweg enthalten<br />

• Vermeiden durch Markieren mit None<br />

und dynamische Berechnung<br />

6 NameError: name ’seq’ is not defined<br />

1 >>> def oh(l, a=[]):<br />

2 a.append("ende")<br />

3 return l+a<br />

4 >>> oh([1,2],[3,4])<br />

5 [1, 2, 3, 4, ’ende’]<br />

6 >>> oh([1,2],[3,4,5])<br />

7 [1, 2, 3, 4, 5, ’ende’]<br />

8 >>> oh([1,2])<br />

9 [1, 2, ’ende’]<br />

10 >>> oh([1,2])<br />

11 [1, 2, ’ende’, ’ende’]<br />

12 >>> oh([1,2])<br />

13 [1, 2, ’ende’, ’ende’, ’ende’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 181 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Parameterübergabe mit Schlüsselwort<br />

Ziel<br />

• Viele Vorgabewerte verwenden, aber<br />

einige Parameter anders<br />

• Zwang Angabe aller früheren<br />

Parameter auflösen<br />

Schlüsselwortparameter<br />

• Parameter über Namen zuweisen<br />

• Name des Parameters als linke Seite<br />

einer Zuweisung im Aufruf<br />

• Reihenfolge der Parameter beliebig<br />

• Für alle Argumente außer den<br />

Schlüsselwortparametern Vorgabe<br />

• Parameter ohne Vorgabewert müssen<br />

als Positions- oder Schlüsselwortparameter<br />

übergeben werden<br />

1 def suche(seq, ele, start=0, ende=None):<br />

2 if ende is None:<br />

3 ende = len(seq)<br />

4 for pos in range(start, ende):<br />

5 if seq[pos] == ele:<br />

6 return pos<br />

1 >>> lis = [1, 2, 3, 4, 5, 6]<br />

2 >>> suche(lis, 2, start=0, ende=len(lis))<br />

3 1<br />

4 >>> suche(lis, 2, 0, len(lis))<br />

5 1<br />

6 >>> suche(lis, 2, ende=len(lis))<br />

7 1<br />

8 >>> suche(lis, 2, start=1, ende=len(lis))<br />

9 1<br />

10 >>> suche(lis, ende=len(lis), ele=2)<br />

11 1<br />

12 >>> suche(lis, 2, ende=1)<br />

13 >>><br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 182 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Argumente sammeln mit * und **<br />

Weitere Positionsparameter *<br />

• Eine Variable am Ende kann mit einem<br />

Stern * versehen werden<br />

• In dieser Variable werden dann alle<br />

weiteren Positionsparameter<br />

gesammelt als Tupel gesammelt<br />

• Realisiert beliebig viele Parameter, wie<br />

zum Beispiel print<br />

Weitere Schlüsselwortparameter **<br />

• Eine Variable ganz am Ende kann mit<br />

zwei Sternen ** versehen werden<br />

11 SyntaxError: non-keyword arg after<br />

• Darin werden alle weiteren<br />

12 keyword arg<br />

Schlüsselwortparameter als Dictionary<br />

gesammelt<br />

• Die Schlüssel sind die<br />

Variablennamen als Strings<br />

1 def params(x, y, *pos, **key):<br />

2 print x, y, pos, key<br />

1 >>> params(1, 2)<br />

2 1 2 () {}<br />

3 >>> params(1, 2, 3, 4, 5)<br />

4 1 2 (3, 4, 5) {}<br />

5 >>> params(1, 2, 3, 4, drei=3, vier=4)<br />

6 1 2 (3, 4) {’drei’: 3, ’vier’: 4}<br />

7 >>> params(1, 2, 3, 4, vier=4, fuenf=5)<br />

8 1 2 (3, 4) {’fuenf’: 5, ’vier’: 4}<br />

9 >>> params(1, 2, 3, fuenf=5, 4, vier=4)<br />

10 File "", line 1<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 183 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Funktionen in Funktionen und die LEGB-Regel<br />

Funktionsdefinitionen während<br />

Funktionsausführung<br />

• Sind erlaubt und sinnvoll<br />

• Umfassen aktuellen Namensraum und<br />

halten ihn fest (Enclosing)<br />

• Von innen nach außen<br />

LEGB-Regel<br />

• LGB-Regel erweitert<br />

• Zwischen Lokal und Global<br />

• Man sucht im umschließenden<br />

Namensraum, in dem die Funktion<br />

definiert wurde<br />

• Dies ist entweder der globale<br />

Namensraum oder ein anderer<br />

Funktionsaufruf als Namensraum<br />

g 1 2 3<br />

e 6 5 3<br />

l 4 5 3<br />

eingeBaut<br />

1 x, y, z = 1, 2, 3<br />

2 def f():<br />

3 x, y = 4, 5<br />

4 def g():<br />

5 x = 6<br />

Global<br />

Eingekapselt<br />

Lokal<br />

6 print "e", x, y, z # 6, 5, 3<br />

7 g()<br />

8 print "l", x, y, z # 4, 5, 3<br />

9 print "g", x, y, z # 1, 2, 3<br />

10 f()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 184 / 326


<strong>Programmieren</strong> in Python<br />

Funktionen<br />

Design-Prinzipien für Funktionen<br />

Parameter verwenden<br />

• Keine globalen Variablen verwenden<br />

• Flexible Gestaltung der übergebbaren<br />

Parameter möglich<br />

• Reduziert Abhängigkeiten<br />

Rückgaben verwenden<br />

• Keine globalen Variablen verwenden<br />

• Modifikation von Parametern meiden<br />

• Mehrere Werte als Tupel zurückgeben<br />

• Modifikation ok in Klassen/Methoden<br />

Verschachtelte Funktionen mit Vorsicht<br />

• Definition einer Funktion in einer<br />

Funktion nur wenn notwendig<br />

• Anonyme Funktionen sind meist<br />

Alternative<br />

1 x, y = 1, 2<br />

2 def sehrboese():<br />

3 global x<br />

4 x = x*y<br />

5 sehrboese()<br />

6<br />

7 x, y = 1, 2<br />

8 def besser(x, y):<br />

9 return x*y<br />

10 x = besser(x, y)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 185 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Programmierung<br />

Anonyme Funktion, Lambda-Ausdrücke<br />

Funktionen sind auch Objekte<br />

• Funktionsobjekte sind normale<br />

Objekte, “first class citizens”<br />

• Funktionsnamen sind an<br />

Funktionsobjekte gebunden<br />

• Definition von Funktionsobjekten und<br />

Bindung an einen Namen mit def<br />

Funktionsobjekte<br />

• Erzeugen eines anonymen<br />

Funktionsobjekte mit lambda<br />

• lambda : <br />

• Funktion mit als Parameter<br />

• Wert der Funktion durch ,<br />

der verwendet<br />

• Zuweisung an Namen und Aufruf<br />

möglich<br />

1 >>> def ink(x):<br />

2 return x+1<br />

3 >>> ink(3)<br />

4 4<br />

5 >>> ink<br />

6 <br />

7 >>> x+1<br />

8 NameError: name ’x’ is not defined<br />

1 >>> lambda x: x+1<br />

2 <br />

3 >>> ink2 = lambda x: x+1<br />

4 >>> ink2<br />

5 <br />

6 >>> ink2(3)<br />

7 4<br />

8 >>> (lambda x: x+1)(3)<br />

9 4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 186 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Programmierung<br />

Funktionales <strong>Programmieren</strong><br />

Funktionales <strong>Programmieren</strong>,<br />

Funktionsaufrufe<br />

• Programm als applikativer<br />

Algorithmus, sukkzesive Reduktion<br />

von Ausdrücken<br />

• Nur Funktionsaufrufe, statt<br />

Kontrollstrukturen<br />

• Primitive zum flexiblen Aufrufen von 10 >>> apply(plus, tup)<br />

Funktionen mit Parametern notwendig<br />

Flexible Parameter<br />

• Erweitere Call Syntax<br />

• * für Positionsparameter, “ausbreiten”<br />

der Parameter<br />

1 >>> def plus(x, y):<br />

2 return x+y<br />

• ** für Schlüsselwortparameter<br />

18 >>> apply(plus, ptub + (4,))<br />

• Alternative: Eingebaute Funktion apply19 6<br />

für Positionsparameter<br />

3<br />

4 >>> tup = (2, 4)<br />

5 >>> plus(tup)<br />

6 TypeError: plus() takes exactly<br />

7 2 arguments (1 given)<br />

8 >>> plus(*tup)<br />

9 6<br />

11 6<br />

12 >>> ptup = (2, )<br />

13 >>> plus(*(ptup + (4,)))<br />

14 6<br />

15 >>> dic = {’x’:2, ’y’:4}<br />

16 >>> plus(**dic)<br />

17 6<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 187 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Funktionale Primitive – map<br />

Funktion auf allen Elementen<br />

• Für alle Objekte von Sequenzen eine<br />

Funktion anwenden<br />

• Schlüsselwort map<br />

6 [2, 3, 4]<br />

• Erster Parameter die Funktion<br />

7 >>> map(lambda x: x+3, [1, 2, 3])<br />

• Ab zweiten Parameter die Sequenzen, 8 [4, 5, 6]<br />

so viele Sequenzen wie die Funktion 9 >>> map(lambda x,y: x+y,<br />

Parameter hat<br />

10 [1, 2, 3], [4, 5, 6])<br />

11 [5, 7, 9]<br />

• Ergebnis ist Liste Funktionsergebnis je<br />

12 >>><br />

Element der Eingabesequenz<br />

• Kürzeste Sequenz bestimmt Länge<br />

des Ergebnisses<br />

Beispiele<br />

• Erhöhe alle Werte um 1<br />

• Addiere die Inhalte einer Liste<br />

paarweise<br />

1 >>> def ink(x):<br />

2 return x+1<br />

3 >>> map(ink, [1, 2, 3])<br />

4 [2, 3, 4]<br />

5 >>> map(lambda x: x+1, [1, 2, 3])<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 188 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Einsatzbeispiel für map<br />

Aufgabe<br />

• Berechne die Liste der Quadratzahlen<br />

von 1 bis 10<br />

Lösung<br />

• for-Schleife<br />

• Liste zusammenbauen<br />

• Zurückgeben<br />

Funktionale Lösung<br />

• Einzeiler mit map<br />

• Liste der Zahlen mit range<br />

• Quadrieren als Lambda-Funktion<br />

• Keine Schleifen<br />

1 def quadratzahlen(von=1, bis=10):<br />

2 lis = []<br />

3 for i in range(von, bis+1):<br />

4 lis.append(i*i)<br />

5 return lis<br />

6<br />

7 print quadratzahlen()<br />

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />

1 def quadratzahlen(von=1, bis=10):<br />

2 return map(lambda x: x*x,<br />

3 range(von, bis+1))<br />

4<br />

5 print quadratzahlen()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 189 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

map illustriert<br />

1 2 3 2 3 4 4 8 16<br />

lambda x, y, z: x+y+z<br />

7 13 23<br />

1 >>> map(lambda x, y, z: x+y+z, [1, 2, 3], [2, 3, 4], [4, 8, 16])<br />

2 [7, 13, 23]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 190 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Funktionale Primitive – filter<br />

Nur Elemente für die Funktion ok ist<br />

• Für alle Objekte einer Sequenz eine<br />

Funktion anwenden, nur die<br />

durchlassen, für die der Funktionswert<br />

äquivalent zu wahr ist<br />

• Schlüsselwort filter<br />

• Erster Parameter die Funktion<br />

• Zweiter Parameter die Sequenz<br />

• Ergebnis ist Liste der ursprünglichen<br />

Elemente, deren Funktionswert<br />

äquivalent zu wahr ist<br />

Beispiele<br />

• Test ob Zahl größer 0<br />

• Test ob Zahl zwischen 1 und 2<br />

• Test ob gerade Zahl<br />

1 >>> def groesser0(x):<br />

2 return x>0<br />

3 >>> filter(groesser0, [1,-1,2,-2,3,-3,4])<br />

4 [1, 2, 3, 4]<br />

5 >>> filter(lambda x: x>0,<br />

6 [1, -1, 2, -2, 3, -3, 4])<br />

7 [1, 2, 3, 4]<br />

8 >>> filter(lambda x: x>0 and x>> filter(lambda x: x%2 == 0,<br />

12 [1, 2, 3, 4, 5])<br />

13 [2, 4]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 191 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Einsatzbeispiel für filter<br />

Aufgabe<br />

• Berechne die Liste der Primzahlen<br />

zwischen 2 und 100<br />

Lösung<br />

• for-Schleife<br />

• Liste zusammenbauen<br />

• Zurückgeben<br />

Funktionale Lösung<br />

• Einzeiler mit filter<br />

• Liste der Zahlen mit range<br />

• Funktion zum Testen ob Primzahl wie<br />

bei for-Schleife<br />

• Keine Schleifen<br />

1 def is_prim(zahl):<br />

2 for teiler in range(2, zahl):<br />

3 if zahl%teiler == 0:<br />

4 return False<br />

5 return True<br />

6 def prims():<br />

7 primzahlen = []<br />

8 for zahl in range(2, 100):<br />

9 if is_prim(zahl):<br />

10 primzahlen.append(zahl)<br />

11 return primzahlen<br />

12 print prims()<br />

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29,<br />

31, 37, 41, 43, 47, 53, 59, 61, 67,<br />

71, 73, 79, 83, 89, 97]<br />

1 def prims():<br />

2 return filter(is_prim, range(2, 100))<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 192 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Funktionale Primitive – reduce<br />

Alle Elemente einer Sequenz mit<br />

einer Funktion kombinieren<br />

• Kumuliere alle Objekte einer<br />

Sequenz über Funktionswerte<br />

auf (foldl)<br />

• Schlüsselwort reduce<br />

• Erster Parameter die Funktion<br />

1 >>> def add(x, y):<br />

2 return x+y<br />

3 >>> def summe(lis):<br />

4 ret = 0<br />

5 for e in lis:<br />

6 ret = e + ret<br />

7 return ret<br />

8 >>> summe(range(101))<br />

9 5050<br />

• Zweiter Parameter die Sequenz 10 >>> reduce(lambda x,y : x+y, range(101), 0)<br />

11 5050<br />

• Dritter Parameter der<br />

12 >>> fak = lambda x: reduce(lambda x,y: x*y,<br />

Anfangswert, meist neutral<br />

13 range(1, x+1), 1)<br />

• Ergebnis ist Auswertung der<br />

linksassoziativen sukkzesiven<br />

Funktionsanwendung<br />

14<br />

15<br />

16<br />

>>> fak(3)<br />

6<br />

>>> fak(6)<br />

17 720<br />

Beispiele: Summieren, Fakultät,<br />

18 >>> reduce(lambda x,y : x+" "+y,<br />

Stringkonkatenation<br />

19 ["Hallo", "tolle", "Welt"], "")<br />

20 ’ Hallo tolle Welt’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 193 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

reduce illustriert<br />

Initialer<br />

Wert<br />

0<br />

1 2 3<br />

4 5 6<br />

0 + 1<br />

1<br />

2 + 1<br />

3<br />

Kumulierte<br />

Werte<br />

3 + 3<br />

6 + 4<br />

6<br />

10<br />

10 + 5<br />

15<br />

15 + 6<br />

21<br />

lambda x, y: x+y<br />

1 >>> add = lambda x,y: x+y<br />

2 >>> reduce(add, [1, 2, 3, 4, 5, 6], 0)<br />

3 21<br />

4 >>> add(add(add(add(add(add(0, 1), 2), 3), 4), 5), 6) # foldl<br />

5 21<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 194 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Definition von map<br />

Primitive für funktionales <strong>Programmieren</strong><br />

1<br />

2<br />

def mymap(func, seq):<br />

ret = []<br />

• Können selbst implementiert werden<br />

3<br />

• Keine Schlüsselwörter, nur vordefiniert 4<br />

for ele in seq:<br />

ret.append(func(ele))<br />

mymap selbst gemacht<br />

5 return ret<br />

• for-Schleife<br />

• Funktion als Parameter<br />

• Aufbau der Ergebnisliste<br />

Verwenden wie eingebautes map<br />

• Implementierung mit mehreren<br />

Sequenzen auch einfach möglich<br />

• Gute Hausaufgabe<br />

1 >>> ink = lambda x: x+1<br />

2 >>> map(ink, [1, 2, 3])<br />

3 [2, 3, 4]<br />

4 >>> mymap(ink, [1, 2, 3])<br />

5 [2, 3, 4]<br />

6 >>> mymap(lambda x: x+1, [1, 2, 3])<br />

7 [2, 3, 4]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 195 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Definition von filter<br />

myfilter selbst gemacht<br />

• for-Schleife<br />

• Funktion als Parameter<br />

• Aufbau der Ergebnisliste<br />

Verwenden wie eingebautes filter<br />

1 def myfilter(func, seq):<br />

2 ret = []<br />

3 for ele in seq:<br />

4 if func(ele):<br />

5 ret.append(ele)<br />

6 return ret<br />

1 >>> filter(lambda x: x>10, range(20))<br />

2 [11, 12, 13, 14, 15, 16, 17, 18, 19]<br />

3 >>> filter(lambda x: x%2, range(20))<br />

4 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]<br />

5 >>> myfilter(lambda x: x>10, range(20))<br />

6 [11, 12, 13, 14, 15, 16, 17, 18, 19]<br />

7 >>> myfilter(lambda x: x%2, range(20))<br />

8 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]<br />

9 >>> myfilter(lambda x: x%2==0, range(20))<br />

10 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 196 / 326


<strong>Programmieren</strong> in Python<br />

Funktionale Primitive<br />

Definition von reduce<br />

myreduce selbst gemacht<br />

• for-Schleife<br />

• Funktion als Parameter<br />

• Aufbau des Ergebniswerts<br />

Verwenden wie eingebautes reduce<br />

1 def myreduce(func, seq, init=None):<br />

2 if init == None:<br />

3 init = seq[0]<br />

4 seq = seq[1:]<br />

5 wert = init<br />

6 for ele in seq:<br />

7 wert = func(wert, ele)<br />

8 return wert<br />

1 >>> add = lambda x,y: x+y<br />

2 >>> reduce(add, range(101))<br />

3 5050<br />

4 >>> myreduce(add, range(101))<br />

5 5050<br />

6 >>> sub = lambda x,y: x-y<br />

7 >>> myreduce(sub, [1,2,3,4,5], 100)<br />

8 85<br />

9 >>> reduce(sub, [1,2,3,4,5], 100)<br />

10 85<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 197 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

List Comprehension<br />

Listentransformation<br />

• Anwendungsgebiet wie funktionales<br />

<strong>Programmieren</strong><br />

• Einfachere Verwendung der<br />

Möglichkeiten von map und filter<br />

zusammen mit lambda und for<br />

Syntax [ for in ]<br />

• statt lambda-Ausdruck<br />

• Durch for wird sukkzesive ein<br />

Wert aus zugewiesen<br />

• Zusätzlich if , als Filter<br />

• Beliebig kombinierbar<br />

Ausdrucksweisen<br />

• Statt verschachtelte for-Schleifen<br />

• Ähnelt math. Mengenschreibweise<br />

1 >>> map(lambda x: x+1, [1,2,3,4])<br />

2 [2, 3, 4, 5]<br />

3 >>> [x+1 for x in [1,2,3,4]]<br />

4 [2, 3, 4, 5]<br />

5 >>> filter(lambda x:x>3, [1,5,2,6,7])<br />

6 [5, 6, 7]<br />

7 >>> [x for x in [1, 5, 2, 6, 7] if x>3]<br />

8 [5, 6, 7]<br />

1 >>> [x**2 for x in range(1, 11)<br />

2 if x % 2 == 0]<br />

3 [4, 16, 36, 64, 100]<br />

{x 2 |1 ≤ x ≤ 10, x mod 2 = 0} =<br />

{4, 16, 36, 64, 100}<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 198 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

List Comprehension – Beispiele mit Zahlen<br />

Quadratzahlen<br />

• Zahlen von 0 bis 9; 1 bis 10<br />

• Ausdruck statt Funktion<br />

Komplexe Definition<br />

• Mischen von Filtern und<br />

Funktionsapplikation<br />

• Aufzählen durch for<br />

Kartesisches Produkt<br />

• Sequenzen kombinieren<br />

• Kartesisches Produkt,<br />

Vollkombination<br />

• Nicht so bei funktionalem<br />

Primitiv map<br />

zip<br />

• Builtin, generiert Tupel<br />

1 >>> [x for x in range(10)]<br />

2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]<br />

3 >>> [x*x for x in range(1, 11)]<br />

4 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />

1 >>> [(x,y) for x in range(4)<br />

2 for y in range(0,5,2)<br />

3 if x < y]<br />

4 [(0, 2), (0, 4), (1, 2), (1, 4),<br />

5 (2, 4), (3, 4)]<br />

1 >>> map(lambda x,y: x+y, range(5), range(5))<br />

2 [0, 2, 4, 6, 8]<br />

3 >>> [x+y for x in range(5) for y in range(5)]<br />

4 [0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6,<br />

5 3, 4, 5, 6, 7, 4, 5, 6, 7, 8]<br />

1 >>> [x+y for (x,y) in zip(range(5),range(5))]<br />

2 [0, 2, 4, 6, 8]<br />

3 >>> zip(range(5), range(5))<br />

4 [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 199 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

List Comprehension – Beispiele mit Text<br />

Wörter ersetzen<br />

• Kleine Zahlen durch Wörter ersetzen<br />

• Für alle Worte, falls das Wort 1,2 oder<br />

3 ist,<br />

• dann ersetze durch Zahlwort und<br />

setze neuen String zusammen<br />

Datei von Zahlen zeilenweise lesen<br />

• Zeilenweise einlesen und aufteilen<br />

(splitten)<br />

• Alle Strings aus Ziffern je Zeile in Liste<br />

von Zahlen umwandeln<br />

• Tupel aus Liste machen<br />

1 >>> trans = {’2’:’zwei’, ’3’: ’drei’,<br />

2 ’4’: ’vier’}<br />

3 >>> s = """2 Sachen und 3 Sachen sind<br />

4 nicht 4 Sachen"""<br />

5 >>> print " ".join([trans[w]<br />

6 if w in trans else w<br />

7 for w in s.split()])<br />

8 zwei Sachen und drei Sachen sind<br />

9 nicht vier Sachen<br />

1 >>> d = "zahlen.dat"<br />

2 >>> file(d).readlines()<br />

3 [’1 2 3\n’, ’42 343 12\n’,<br />

4 ’8 77 223\n’, ’23 43\n’,<br />

5 ’45 3 3 66 7\n’]<br />

6 >>> [tuple(map(int, line.split()))<br />

7 for line in file(d)]<br />

8 [(1, 2, 3), (42, 343, 12), (8, 77, 223),<br />

9 (23, 43), (45, 3, 3, 66, 7)]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 200 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Funktionale Programmierung – Zusammenfassung<br />

Vorteile<br />

• Verminderung der Fehleranfälligkeit, zum Beispiel sind viele Indexfehler gar nicht<br />

mehr formulierbar<br />

• Kompakter, ausdrucksstarker Code nahe an der Spezifikation<br />

• Gut zu lesen und zu verstehen, wenn nicht zu viel in einer Zeile passiert<br />

• Seiteneffektfrei, muss man natürlich auch darauf achten<br />

Nachteile<br />

• Syntax/Ausdrucksweise etwas gewöhnungsbedürftig<br />

• Funktionales Denken erfordert etwas Einarbeitungszeit<br />

Verbreitung<br />

• Funktionale Primitive in allen höheren Programmiersprachen zu finden (Ruby, Perl,<br />

Lisp, C#)<br />

• Lambda-Ausdrücke sind in C# für LINQ, in Java ab 8<br />

• MapReduce, Framework (Google) zum Suchen in riesigen Datenmenge<br />

Online-Referenzen<br />

• http://www-106.ibm.com/developerworks/linux/library/l-prog.html<br />

• http://www.freenetpages.co.uk/hp/alan.gauld/tutfctnl.htm<br />

• . . .<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 201 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Module<br />

Warum Module?<br />

• Wiederverwendung von Code<br />

• Bereitstellung von allgmein<br />

nutzbaren Diensten und<br />

Bibliotheken<br />

• Unterteilung des Namensraums<br />

bei großen Projekten<br />

Python Module<br />

• Jede Python-Datei (Endung mit<br />

.py) ist ein Modul<br />

• C-Erweiterungen sind Modul<br />

• Nutzen mit import, from<br />

Suche nach Dateien/Module<br />

• Umgebungsvariable PYTHONPATH<br />

• Abhängig von Wert in sys.path<br />

1 >>> import sys<br />

2 >>> sys.path<br />

3 [’’, # sucht auch im akt. Verzeichnis<br />

4 ’/usr/lib/python2.7’,<br />

5 ’/usr/lib/python2.7/plat-linux2’,<br />

6 ’/usr/lib/python2.7/lib-tk’,<br />

7 ’/usr/lib/python2.7/lib-old’,<br />

8 ’/usr/lib/python2.7/lib-dynload’,<br />

9 ’/usr/local/lib/python2.7/dist-packages’,<br />

10 ’/usr/lib/python2.7/dist-packages’,<br />

11 ’/usr/lib/python2.7/dist-packages/PIL’,<br />

12 ’/usr/lib/python2.7/dist-packages/gst-0.10’,<br />

13 ’/usr/lib/python2.7/dist-packages/gtk-2.0’,<br />

14 ’/usr/lib/pymodules/python2.7’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 202 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Definieren von Modulen<br />

Ein Modul ist eine Datei<br />

• Mit der Endung .py,<br />

oder vorkompiliert .pyc<br />

• In einem Verzeichnis<br />

• Beliebiger Python-Code<br />

• Keine Python-Schlüsselwörter als<br />

Dateiname<br />

Im Suchpfad erreichbar<br />

• Vorgabe ist aktuelles Verzeichnis und<br />

Standard-Bibliothek von Python<br />

• sys.path<br />

meinmodul.py<br />

1 # Modul meinmodul, meinmodul.py<br />

2 # Variablen und Funktionen<br />

3<br />

4 deutsch = "deutsch"<br />

5 englisch = "englisch"<br />

6<br />

7 sprache = deutsch<br />

8<br />

9 def drucke(x):<br />

10 print x<br />

11<br />

12 def gruss():<br />

13 if sprache == deutsch:<br />

14 drucke("Hallo Modul Welt")<br />

15 else:<br />

16 drucke("Hello module world")<br />

17<br />

18 print "meinmodul geladen"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 203 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Importieren von Modulen<br />

Modul importieren<br />

• Im aktuellen Verzeichnis<br />

• Wechseln mit os.chdir()<br />

• Importiert Modul mit dem<br />

Namen <br />

• Objekte nur über den<br />

Modul-Präfix erreichbar<br />

Namen von Modulen importieren<br />

• Modul selbst nicht sichtbar<br />

• Alle Namen im aktuellen<br />

Namensraum verfügbar<br />

• Aber an Objekt in Modul<br />

gebunden<br />

• * für alle Namen außer Namen,<br />

die mit einem Unterstrich _<br />

beginnen<br />

import [, ]*<br />

1 $ ls meinmodul.py<br />

2 meinmodul.py<br />

3 $ python<br />

4 >>> import meinmodul<br />

5 meinmodul geladen<br />

6 >>> meinmodul.gruss()<br />

7 Hallo Modul Welt<br />

8 >>> meinmodul.sprache=meinmodul.englisch<br />

9 >>> meinmodul.gruss()<br />

10 Hello module world<br />

11 >>> meinmodul.sprache = englisch<br />

12 NameError: name ’englisch’ is not defined<br />

from import [, ]*<br />

1 >>> from meinmodul import gruss<br />

2 >>> gruss()<br />

3 Hallo Modul Welt<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 204 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Module und Namensräume<br />

Ausführung beim Import<br />

• Modulanweisungen laufen nur beim<br />

ersten Import einmal ab<br />

• Achtung bei Entwicklung, IDLE<br />

restart führt neu aus, ohne restart<br />

werden Module nicht neu ausgeführt<br />

Modulattribute<br />

• Zuweisungen und<br />

10 {’drucke’: >> import meinmodul<br />

2 meinmodul geladen<br />

3 >>> dir(meinmodul)<br />

4 [’__builtins__’, ’__doc__’, ’__file__’,<br />

5 ’__name__’, ’__package__’, ’deutsch’,<br />

6 ’drucke’, ’englisch’, ’gruss’,<br />

7 ’sprache’]<br />

8 >>> import meinmodul<br />

9 >>> meinmodul.__dict__<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 205 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Hauptprogramm mit main<br />

Ziel<br />

• Ausführen eins Code-Blocks nur, wenn<br />

es als Hauptprogramm gestartet<br />

wurde; nicht wenn es importiert wurde<br />

• Simulieren der main-Funktion/Methode<br />

von C/Java<br />

• Häufig zum Testen eines Moduls<br />

verwendet<br />

Umsetzung, Idiom<br />

• Der Name des interaktiven oder<br />

Haupt-Moduls ist ’__main__’<br />

• Test auf Name und bedingt ausführen<br />

main.py<br />

1 import sys<br />

2<br />

3 def drucke(x):<br />

4 print "|%s|" % x<br />

5<br />

6 if __name__ == ’__main__’:<br />

7 print "drucker"<br />

8 for ele in sys.argv[1:]:<br />

9 drucke(ele)<br />

1 >>> import main<br />

2 >>> main.drucke("hallo")<br />

3 |hallo|<br />

4 >>> main.drucke("hello")<br />

5 |hello|<br />

$ python main.py hallo hello<br />

drucker<br />

|hallo|<br />

|hello|<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 206 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Qualifikation von Namen<br />

Einfacher Name<br />

• Auflösung über LEGB-Regel<br />

Qualifikation<br />

• .<br />

• Im Geltungsbereich des Moduls<br />

• Die gleiche Notation wie bei Objekten<br />

Qualifikationspfade<br />

• ..<br />

• Nur im genau spezifizierten<br />

Geltungsbereich<br />

Qualifikation funktioniert für alle Objekte:<br />

Module, Klassen, Typen, . . .<br />

qual.py<br />

1 import os<br />

2 name = "Name"<br />

1 >>> import qual<br />

2 >>> name<br />

3 NameError: name ’name’ is not defined<br />

4 >>> qual.name<br />

5 ’Name’<br />

6 >>> os.getcwd()<br />

7 NameError: name ’os’ is not defined<br />

8 >>> qual.os.getcwd()<br />

9 ’/home/mi/ssinn001/prog3’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 207 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Erzwingen von Neuladen<br />

Import von Modulen<br />

• Module werden beim ersten Import<br />

ausgeführt<br />

• Beim zweiten importieren wird nur ein<br />

neuer Namen wieder an das<br />

Modulobjekt gebunden<br />

• Zweiter Import sinnvoll um Modul im<br />

aktuellen Namensraum zu haben<br />

reload()<br />

• Lädt Modul neu, erstellt neues<br />

Modulobjekt<br />

• Wichtig beim Entwicklen, IDLE kein<br />

restart<br />

• Code-Änderungen werden erst dann<br />

wirksam<br />

m1.py<br />

1 import meinmodul<br />

m2.py<br />

1 import meinmodul<br />

m3.py<br />

1 import m1<br />

2 import m2<br />

3 print m1.meinmodul.gruss<br />

4 print m2.meinmodul.gruss<br />

5 m2.meinmodul = reload(m2.meinmodul)<br />

6 print m2.meinmodul.gruss<br />

1 $ python m3.py<br />

2 meinmodul geladen<br />

3 <br />

4 <br />

5 meinmodul geladen<br />

6 <br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 208 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Warum nicht from import *<br />

Verunreinigung des Namensraums<br />

• Namenskonflikte möglich<br />

• Gleiche Namen in Modulen würden im<br />

importierenden Modul überschreiben,<br />

der letzte gewinnt<br />

Importieren ist Namensbindung<br />

• Ist nicht immer was erwartet wird<br />

• Im Beispiel wird der Name sprache<br />

importiert<br />

• Die Funktion gruss verwendet natürlich<br />

noch sprache im Modul meinmodul<br />

from import * vermeiden<br />

Wenn Modulname zu lang, as<br />

1 >>> from meinmodul import *<br />

2 meinmodul geladen<br />

3 >>> gruss()<br />

4 Hallo Modul Welt<br />

5 >>> sprache = "englisch"<br />

6 >>> gruss()<br />

7 Hallo Modul Welt<br />

8 >>> import meinmodul<br />

9 >>> meinmodul.sprache = "englisch"<br />

10 >>> gruss()<br />

11 Hello module world<br />

import as <br />

1 >>> import meinmodul as mm<br />

2 meinmodul geladen<br />

3 >>> mm.gruss()<br />

4 Hallo Modul Welt<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 209 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Warum nicht from import *<br />

1 >>> from meinmodul import *<br />

2 meinmodul geladen<br />

3 >>> gruss()<br />

4 Hallo Modul Welt<br />

5 >>> sprache = "englisch"<br />

6 >>> gruss()<br />

7 Hallo Modul Welt<br />

8 >>> import meinmodul<br />

9 >>> meinmodul.sprache = "englisch"<br />

0 >>> gruss()<br />

1 Hello module world<br />

import as <br />

1 >>> import meinmodul as mm<br />

2 meinmodul geladen<br />

3 >>> mm.gruss()<br />

4 Hallo Modul Welt<br />

__main__<br />

deutsch<br />

englisch<br />

sprache<br />

drucke<br />

gruss<br />

meinmodul<br />

deutsch<br />

englisch<br />

sprache<br />

drucke<br />

gruss<br />

__main__<br />

meinmodul<br />

mm<br />

“deutsch“<br />

“englisch“<br />

lambda...<br />

lambda...<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 210 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Datenkapselung und Daten verstecken<br />

meinmodul.py (Erweiterung)<br />

Datenkapselung<br />

1 #...<br />

• Kapselung ist Ziel von Modulen<br />

2 def andere_sprache(s):<br />

3<br />

•<br />

global sprache<br />

Nicht erzwungen in Python, kein<br />

4 if s in [deutsch, englisch]:<br />

public, private, protected<br />

5 sprache = s<br />

• Nur “unhöflich”, gegen Konvention<br />

6 else:<br />

Daten verstecken<br />

7 raise Exception("Sprache %s" % s)<br />

• Konvention mit _<br />

•<br />

1<br />

Durchgriff möglich<br />

>>> import meinmodulgross as mm<br />

2 >>> mm.gruss()<br />

• Nicht importiert bei *<br />

3 Hallo Modul Welt<br />

Konventionen<br />

4 >>> mm.andere_sprache(mm.englisch)<br />

5<br />

• Keine Modulattribute ändern, nur lesen >>> mm.gruss()<br />

6 Hello module world<br />

• Nur Funktionen verwenden<br />

7 >>> mm.andere_sprache("portugiesisch")<br />

• Keine Funktionen mit _ am Anfang 8 Exception: Sprache portugiesisch<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 211 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Pakete/Packages – Ordner als Module<br />

Flache Struktur<br />

• Viele Module flach im Ordner ok<br />

• In großem Projekt nicht ausreichend<br />

• Standardbibliotheken so nicht gut<br />

strukturierbar<br />

• Besser Hierarchie von Ordnern<br />

Package<br />

• Ordner als Hierachiestufen bei der<br />

Namensqualifikation (wie Java)<br />

• Wenn ein Ordner die Datei<br />

__init__.py enthält, dann ist der<br />

Ordner ein Package<br />

• __init__.py kann Initialisierungscode<br />

der Package enthalten, zum Beispiel<br />

Module nachladen und Namensraum<br />

ausgestalten<br />

paket/a.py<br />

1 s = "hallo"<br />

2 def machgross(s):<br />

3 return s.upper()<br />

paket/b.py<br />

1 import string<br />

2 def machklein(s):<br />

3 return s.lower()<br />

paket/__init__.py<br />

1 import a<br />

2 from a import s<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 212 / 326


<strong>Programmieren</strong> in Python<br />

List Comprehension<br />

Pakete/Packages – Beispiel Verwendung<br />

paket/a.py<br />

1 >>> import paket<br />

1 s = "hallo"<br />

2 >>> paket.a<br />

2 def machgross(s):<br />

3 <br />

3 return s.upper()<br />

4 >>> paket.a.machgross("ab")<br />

5 ’AB’<br />

paket/b.py<br />

6 >>> paket.a.s, paket.s<br />

1 import string<br />

7 (’hallo’, ’hallo’)<br />

2 def machklein(s):<br />

8 >>> paket.b<br />

3 return s.lower()<br />

9 AttributeError: ’module’ object has<br />

10 no attribute ’b’<br />

paket/__init__.py<br />

11 >>> import paket.b<br />

12 >>> paket.b<br />

1 import a<br />

13 <br />

2 from a import s<br />

14 >>> paket.b.string.lower("hallo")<br />

15 ’hallo’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 213 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Objektorientierung in Python<br />

Ähnlich zu Java<br />

• Schlüsselworte, Referenzsemantik<br />

• Attribute, Vererbung, Polymorphismus<br />

• Einfach, Sprache mit OO konzipiert<br />

Unterschiede, neue Features<br />

• Dynamische Attribute, Attributsuche<br />

• Mehrfachvererbung, keine Schnittstellen<br />

• Kapselung (Komposition) nur per Konvention,<br />

aber Properties<br />

• Operatorenüberladung, Duck-Typing (reagieren auf<br />

Index-Zugriff, Ausgabe, Slicen)<br />

• Selbst erstellte Klassen verhalten sich wie<br />

eingebaute Typen<br />

• Alles! ist ein Objekt (Zahlen, Module, . . . )<br />

1 >>> i=3<br />

2 >>> type(i)<br />

3 <br />

4 >>> isinstance(i, int)<br />

5 True<br />

6 >>> i.__add__<br />

7 <br />

9 >>> i.__add__(4)<br />

10 7<br />

11 >>> i.__mul__(4)<br />

12 12<br />

13 >>> object<br />

14 <br />

15 >>> issubclass(int, object)<br />

16 True<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 214 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassen<br />

Klassendefinition<br />

• class: Schlüsselwort<br />

• : Name für die Klasse<br />

• object: Wurzelklasse, immer angeben<br />

• : Dokumentationsstring<br />

• : Funktionsdefinitionen für Methoden<br />

Besonderheiten<br />

• Erstes Methodenargument ist immer Instanzobjekt<br />

• Per Konvention der Name self, in Java wäre es this<br />

• Spezielle Methode __init__ statt Konstruktor<br />

• Attribute sind Klassenattribute und nicht, wie von<br />

Java erwartet, Instanzattribute<br />

• Instanzattribute dynamisch (__init__) in<br />

Namensraum self schreiben<br />

class (object):<br />

[]<br />

<br />

klasse.py<br />

1 class A(object):<br />

2 "Eine Klasse A"<br />

3 def __init__(self):<br />

4 self.a = 17<br />

5 def inca(self):<br />

6 self.a += 1<br />

7 print A<br />

$ python klasse.py<br />

<br />

Ausführung erzeugt<br />

Klassenobjekt (Klassen<br />

sind Objekte!), binden<br />

Klassenname an<br />

Klassenobjekt<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 215 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassendefinition – Beispiel Stack<br />

Stack auf Basis von Listen (Komposition)<br />

• Initialisierung der Instanzvariable<br />

liste mit leere Liste<br />

• self ist immer das erste Argument bei<br />

Methoden<br />

• self muss explizit aufgeführt werden<br />

bei der Definition<br />

• self ist Namensraum einer Instanz<br />

• Weitere Argumente bei Methoden<br />

erlaubt<br />

• Manipulation der Instanzattribute in<br />

self sollte nur durch Methoden<br />

erfolgen<br />

• Keine get/set Methoden schreiben!<br />

• Später mit Properties<br />

1 class Stack(object):<br />

2 "Stack-Klasse mit Python Listen"<br />

3<br />

4 def __init__(self):<br />

5 self.liste = []<br />

6<br />

7 def push(self, elem):<br />

8 self.liste.append(elem)<br />

9<br />

10 def pop(self):<br />

11 del self.liste[-1]<br />

12<br />

13 def top(self):<br />

14 return self.liste[-1]<br />

15<br />

16 def clear(self):<br />

17 self.liste = []<br />

18<br />

19 def empty(self):<br />

20 return self.liste == []<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 216 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Generieren und Nutzen von Instanzen<br />

Klassendefinition<br />

• Klassenname ist Name gebunden an<br />

Klassenobjekt<br />

• Im Beispiel Stack in stack.py<br />

Instanziierung<br />

• Neue Instanz durch Aufruf<br />

Klassennamen (kein new)<br />

• Implizit wird __init__ aufgerufen<br />

• Zuweisung der Instanz an Namen<br />

• Name referenziert dann Instanzobjekt<br />

Nutzen wie gewohnt<br />

• Kapselung nicht erzwungen aber<br />

Konvention<br />

>>> from stack import Stack<br />

>>> Stack<br />

<br />

>>> s = Stack()<br />

<br />

>>> s.empty()<br />

True<br />

>>> s.push(1); s.push(2); s.push(3)<br />

>>> s.liste # Boese, nicht machen<br />

[1, 2, 3]<br />

>>> s.empty()<br />

False<br />

>>> s.top()<br />

3<br />

>>> s.pop()<br />

>>> s.top()<br />

2<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 217 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Vererbung und Mehrfachvererbung<br />

Vererbung<br />

• Superklassen in Klammern dahinter<br />

• object nur dann nicht mehr notwendig<br />

1<br />

class ( [, ]*):<br />

...<br />

fancystack.py<br />

from stack import Stack<br />

• Ganz ohne Superklassen werden es<br />

2<br />

Old-Style Klassen, deprecated<br />

3 class FancyStack(Stack):<br />

• Mehrfachvererbung möglich<br />

Mehrfachvererbung<br />

4<br />

5<br />

def peek(self, i):<br />

return self.liste[i]<br />

• Suche nach Attribut oder<br />

Methodenname<br />

• Erst in aktueller Klasse<br />

• Dann in Superklassen wie definiert<br />

• Erst alle Superklassen der<br />

Superklassen<br />

• Kurz: von links nach rechts,<br />

Tiefensuche*<br />

9 1<br />

*In der Realität etwas komplizierter<br />

http://www.python.org/download/releases/2.3/mro/<br />

1 >>> from fancystack import FancyStack<br />

2 >>> s = FancyStack()<br />

3 >>> s<br />

4 >> s.push(1); s.push(2); s.push(3)<br />

6 >>> s.peek(2)<br />

7 3<br />

8 >>> s.peek(0)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 218 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassen- und Instanzvariablen<br />

Instanzvariablen<br />

• Zuweisung an durch self<br />

aufgespannten Namensraum<br />

•<br />

5<br />

Unabhängig von allen anderen Namen def show_verbose(self):<br />

6 print "Klasse", K.verbose<br />

• Entspricht Instanzvariablen in Java<br />

7 print "Instanz", self.verbose<br />

Klassenvariablen<br />

• Initialisierung als Attribute<br />

• In durch Klassennamen<br />

aufgespannten Namensraum<br />

• Entspricht static Variablen in Java<br />

• Achtung: Syntax wie Instanzvariablen<br />

in Java<br />

1 class K(object):<br />

2 verbose = 1<br />

3 def __init__(self, v):<br />

4 self.verbose = v<br />

1 >>> K.verbose<br />

2 1<br />

3 >>> i = K(2)<br />

4 >>> i.verbose<br />

5 2<br />

6 >>> K.verbose<br />

7 1<br />

8 >>> i.show_verbose()<br />

9 Klasse 1<br />

10 Instanz 2<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 219 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassen- und Instanzvariablen – Attributsuche<br />

Suchordnung<br />

• Erst Instanz, dann Klasse, dann<br />

Superklassen<br />

Suche in self<br />

• Wenn keine Instanzvariable vorliegt,<br />

wird die der Klasse gelesen,<br />

Zeile 2<br />

Zur Laufzeit änderbar<br />

• Instanzvariable zur Laufzeit<br />

hinzufügbar, Zeile 4<br />

Klassenvariable nur noch qualifiziert<br />

• Zugriff über Namensraum der Klasse,<br />

Zeile 7<br />

1 class K(object):<br />

2 verbose = 1<br />

3 def __init__(self):<br />

4 pass<br />

1 >>> k = K()<br />

2 >>> k.verbose<br />

3 1<br />

4 >>> k.verbose = 2<br />

5 >>> k.verbose<br />

6 2<br />

7 >>> K.verbose<br />

8 1<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 220 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassenmethoden<br />

Statische Methoden<br />

• Klassenmethode, bezieht sich nicht<br />

auf Instanz, in Java static<br />

• Syntax: Dekorator @staticmethod<br />

• Kein erstes Argument self mehr<br />

vorhanden<br />

Klassenmethode<br />

• Klassenmethode, wobei das erste<br />

Argument die Klasse ist<br />

• Syntax: Dekorator @classmethod<br />

• Überschreiben möglich,<br />

fortgeschrittenes Konzept, vermeiden<br />

1 class K(object):<br />

2 zaehle = 1<br />

3 def __init__(self):<br />

4 self.zahl = 17<br />

5 @staticmethod<br />

6 def statisch(x):<br />

7 K.zaehle += x<br />

8 @classmethod<br />

9 def klassenmethode(cls, x):<br />

10 cls.zaehle += x<br />

1 >>> k = K()<br />

2 >>> k.zaehle, K.zaehle<br />

3 (1, 1)<br />

4 >>> k.statisch(3)<br />

5 >>> K.zaehle<br />

6 4<br />

7 >>> k.klassenmethode(3)<br />

8 >>> K.zaehle<br />

9 7<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 221 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Dekorator<br />

Dekoratorfunktion<br />

• Funktion, die mindestens eine<br />

Funktion als Argument hat und eine<br />

Funktion zurückgibt; einpacken<br />

• Ziel: Verhalten und Syntax einer<br />

Funktion ändern<br />

• Beispieleinsatz: statische Methoden<br />

• Beispiel: statisch in Zeilen 6-8, in<br />

Python


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Alternative zu Klassenmethoden<br />

1 _kzaehle=1 # nicht importieren bei<br />

Klassenscope meist nicht notwendig<br />

*<br />

2 def statisch(x):<br />

• In Java kein umfassende<br />

3 global _kzaehle<br />

Modulkonzept vorhanden, keine Werte 4 _kzaehle += x<br />

auf globaler Ebene<br />

5 class K(object):<br />

6<br />

• Statische Methoden und<br />

def __init__(self):<br />

7 self.zahl = 17<br />

Klassenvariablen um zu kompensieren<br />

• In Python Kompensation nicht<br />

notwendig<br />

Nutzen Modulkonzept<br />

1 def statisch(x):<br />

2 K.zaehle += x<br />

3 class K(object):<br />

• Statt Klassenvariable Modulvariable<br />

4 zaehle = 1<br />

5 def __init__(self):<br />

• Statt statische Methode Modulfunktion<br />

6 self.zahl = 17<br />

• Häufig passender<br />

1 >>> k = K()<br />

2 >>> statisch(3)<br />

3 >>> K.zaehle<br />

4 4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 223 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassen und Instanzen sind Namensräume<br />

Nicht qualifizierte Namen nach<br />

Geltungsbereichen<br />

• x=wert; weist an lokalen Namen zu<br />

• x; Zugriff mit LEGB-Regel<br />

Qualifizierte Namen<br />

• Namensraum des Objekts<br />

1 x = 4<br />

2 class K1(object):<br />

3 def __init__(self):<br />

4 self.x = 1<br />

5 class K2(K1):<br />

6 x = 3<br />

7 def __init__(self):<br />

8 K1.__init__(self)<br />

9<br />

• def f(self):<br />

Suche erst in aktueller Instanz,<br />

10 self.x = 2<br />

beinhaltet was durch Superklassen an<br />

11 def showx(self):<br />

Instanz geändert wurde,<br />

12 print self.x,<br />

dann erst in Klassenscope<br />

13 k = K2(); k.showx()<br />

• Nicht im definierenden Modul<br />

14 k.f(); k.showx()<br />

15 del k.x; k.showx()<br />

16 del K2.x; k.showx()<br />

1 1 2 3<br />

2 AttributeError: ’K2’ object<br />

3 has no attribute ’x’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 224 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Klassen, Selbstbeobachtung<br />

Umsetzung, Interna<br />

• Attribute mit doppelten Unterstrichen<br />

• Direkter Zugriff nur wenn notwendig<br />

Klassen<br />

• Name, Superklassen<br />

Instanzen<br />

• Klasse der Instanz<br />

• Namensraum mit __dict__<br />

• Realisiert mit Dictionaries<br />

Selbst ausprobieren!<br />

1 class K(object):<br />

2 verbose = 1<br />

3 def __init__(self): pass<br />

1 >>> from klasse import K<br />

2 >>> K.__name__ # der Name<br />

3 ’K’<br />

4 >>> K.__bases__ # die Superklassen<br />

5 (,)<br />

6 >>> k = K()<br />

7 >>> k.__class__, k.__dict__<br />

8 (, {})<br />

9 >>> dir(k)<br />

10 [’__class__’, ’__delattr__’, ’__dict__’,<br />

11 ’__doc__’, ’__format__’, ’__getattribute_<br />

12 ’__hash__’, ’__init__’, ’__module__’,<br />

13 ’__new__’, ’__reduce__’, ’__reduce_ex__’,<br />

14 ’__repr__’, ’__setattr__’, ’__sizeof__’,<br />

15 ’__str__’, ’__subclasshook__’, ’__weakref<br />

16 ’verbose’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 225 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Properties statt Getter und Setter<br />

Durchgriff auf Attribute<br />

• Ist in Python in Ordnung<br />

• Keine Getter und Setter<br />

• Man kann nachträglich ändern und<br />

Kontrolle wieder erlangen<br />

Properties<br />

• Eigentliches Attribut verstecken, _ am<br />

Namensanfang als Hinweis<br />

• Definition Getter, Setter und Löschen<br />

• Definition des Attributs mit<br />

property(get, set, delete, doc)<br />

1 class Name(object):<br />

2<br />

3 def __init__(self):<br />

4 self._vorname = "Max"<br />

5<br />

6 def get_vorname(self):<br />

7 return self._vorname<br />

8<br />

9 def set_vorname(self, value):<br />

10 oktypes = [str, unicode]:<br />

11 if type(value) not in oktypes:<br />

12 msg = "vorname kein String"<br />

13 raise AttributeError(msg)<br />

14 self._vorname = value<br />

15<br />

16 vorname = property(get_vorname,<br />

17 set_vorname,<br />

18 None,<br />

19 "Vorname als String/Unicode")<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 226 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Properties verwenden<br />

Auf Klassenebene zugewiesenes Attribut<br />

wie Instanzvariable verwenden<br />

• Automatisch Aufruf der passenden<br />

Methode<br />

• Wenn nicht angegeben, dann<br />

Verwendung nicht möglich<br />

Durchgriff: Immer noch möglich, nicht<br />

machen<br />

1 >>> name = Name()<br />

2 >>> name.vorname<br />

3 ’Max’<br />

4 >>> name.vorname = ’Susi’<br />

5 >>> name.vorname<br />

6 ’Susi’<br />

7 >>> name.vorname = 17<br />

8 AttributeError: vorname kein String<br />

9 >>> name.vorname<br />

10 ’Max’<br />

11 >>> del name.vorname<br />

12 AttributeError: can’t delete attribute<br />

13 >>> name.vorname<br />

14 ’Max’<br />

15<br />

16 >>> n._vorname = 17<br />

17 >>> n.vorname<br />

18 17<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 227 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Überladen von Operatoren – Motivation<br />

Ziel<br />

• Rechnen Modulo einer Zahl mod<br />

• Alle Ergebnisse sollen zwischen 0 und<br />

mod-1 liegen<br />

Lösung<br />

• Klasse Modulo<br />

• Initialisiert mit Wert mod<br />

• Implementierung der Operationen<br />

durch Standardoperationen, aber<br />

Anpassung modulo<br />

• Funktioniert, Benutzung nicht intuitiv<br />

Wunsch<br />

• Benutzen der Modulo-Instanzen wie<br />

eingebaute Zahlen<br />

1 class Modulo(object):<br />

2 "Rechnen modulo einer Zahl"<br />

3 def __init__(self, mod, zahl=0):<br />

4 self.mod = mod<br />

5 self.zahl = zahl<br />

6 def wert(self):<br />

7 return self.zahl<br />

8 def add(self, z):<br />

9 zahl, mod = self.zahl, self.mod<br />

10 self.zahl = (zahl+z) % mod<br />

1 >>> m = Modulo(7)<br />

2 >>> m.wert()<br />

3 0<br />

4 >>> m.add(4); m.wert()<br />

5 4<br />

6 >>> m.add(5); m.wert()<br />

7 2<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 228 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Überladen von Operatoren – Umsetzung<br />

Vordefinierte Funktionsnamen<br />

• Werden gerufen bei Anwendung von<br />

Operatoren<br />

• Beginnen und enden mit zwei<br />

Unterstrichen<br />

• Definition neuer Operatoren nicht<br />

möglich<br />

Beispiele<br />

• __repr__: Repräsentation bei<br />

interaktiver Ausgabe, es wird String<br />

erwartet, Java’s toString ist __str__<br />

• __add__: Wird gerufen bei<br />

linksseitigem + Operator<br />

Achtung: Eingebautes + liefert immer<br />

ein neues Objekt, auch so machen<br />

1 ...<br />

2 def __repr__(self):<br />

3 return str(self.zahl)<br />

4 __str__ = __repr__<br />

5 def __add__(self, z):<br />

6 n = Modulo(self.mod, self.zahl)<br />

7 n.add(z)<br />

8 return n<br />

1 >>> m = Modulo(7)<br />

2 >>> m<br />

3 0<br />

4 >>> m.add(4)<br />

5 >>> m<br />

6 4<br />

7 >>> m+5<br />

8 2<br />

9 >>> m<br />

10 4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 229 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Überladbare Operatoren – Auszug<br />

• __init__: Konstruktorersatz, __init__ der Superklasse nicht automatisch gerufen<br />

• __del__: Destruktorersatz, beim expliziten Löschen und bei Garbage-Collection<br />

• __add__, __or__: Operator +, |<br />

• __repr__: Drucken (print), Konvertierung<br />

• __call__: Funktionsaufruf ()<br />

• __getattr__, __getattribute__: Qualifikation<br />

• __getitem__: Indizierung, auch von in-Operator verwendet<br />

• __setitem__: Zuweisung über Index<br />

• __getslice__: Teilbereichsbildung<br />

• __len__: Länge<br />

• __cmp__: Vergleich<br />

• __eq__, __ne__: Gleichheit (==), Ungleichheit(!=)<br />

• __radd__: Rechtsseitiger Operator +<br />

Details und weitere Operatoren in der Dokumentation<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 230 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Von eingebauten Klassen ableiten<br />

Beispiel eigenes Wörterbuch<br />

• Verhalten wie dict, aber nur Strings<br />

als Schlüssel<br />

• Alles andere gleich<br />

Umsetzung<br />

• Von dict ableiten, Vererben alternativ<br />

zu Komposition<br />

• Überladen von __setitem__<br />

• Nutzen von __setitem__ der<br />

Superklasse (Achtung: sonst<br />

unendliche Rekursion)<br />

1 class strdict(dict):<br />

2 def __setitem__(self, key, value):<br />

3 if type(key) != str:<br />

4 msg = "nur String als Key"<br />

5 raise AttributeError(msg)<br />

6 dict.__setitem__(self, key, value)<br />

1 >>> dic = dict()<br />

2 >>> dic[1] = 2<br />

3 >>> dic["eins"] = 2<br />

4 >>> dic<br />

5 {1: 2, ’eins’: 2}<br />

6 >>> strdic = strdict()<br />

7 >>> strdic[1] = 2<br />

8 AttributeError: nur String als Key<br />

9 >>> strdic["eins"] = 2<br />

10 >>> strdic<br />

11 {’eins’: 2}<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 231 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Iteratoren für eigene Klassen<br />

for-Kontrollstruktur<br />

• Einfaches Iterieren über Sequenzen<br />

• Funktioniert mit Iterator-Objekt<br />

• next gibt nächstes Element zurück<br />

• Ausname StopIteration, wenn kein<br />

Element mehr verfügbar<br />

• Ähnlich zu Java<br />

iter-Methode, eingebaut<br />

3<br />

• Holt von Objekt Iterator, wenn möglich<br />

>>> it<br />

4 <br />

• Implizit und explizit verwendbar<br />

5 >>> it.next()<br />

• Beispiel mit Listen<br />

1 >>> l = [1, 2, 3]<br />

2 >>> lis = [1, 2, 3]<br />

3 >>> for ele in lis:<br />

4 print ele<br />

5 1<br />

6 2<br />

7 3<br />

1 >> lis = [1, 2, 3]<br />

2 >>> it = iter(l)<br />

6 1<br />

7 >>> it.next()<br />

8 2<br />

9 >>> it.next()<br />

10 3<br />

11 >>> it.next()<br />

12 StopIteration<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 232 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Iteratoren für eigene Klassen – Instanz selbst<br />

Selbst implementieren in der Klasse<br />

• Überladen von __iter__<br />

• Erwartet Iterator-Objekt<br />

Bewertung<br />

• Zum Beispiel sich selbst, wenn<br />

Methode next definiert ist<br />

• Keine Schnittstellen, Duck-Typing<br />

• Einfach zu realisieren<br />

1 class Iterselbst(object):<br />

2 def __init__(self):<br />

3 self.lis = [1,2,3]<br />

4 def __iter__(self):<br />

5 self.index = 0<br />

6 return self<br />

7 def next(self):<br />

8 if self.index >= len(self.lis):<br />

9 raise StopIteration<br />

10 self.index += 1<br />

11<br />

• return self.lis[self.index-1]<br />

Nachteil: Nur ein Iterator gleichzeitig je<br />

Instanz, da aktueller Zustand nur<br />

1 >>> its = Iterselbst()<br />

einmal in der Instanz gespeichert ist<br />

2 >>> for ele in its:<br />

3 print ele,<br />

4 1 2 3<br />

5 >>> its = Iterselbst()<br />

6 >>> it1, it2 = iter(its), iter(its)<br />

7 >>> it1.next(), it2.next()<br />

8 (1, 2)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 233 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Iteratoren für eigene Klassen – Iterator-Klasse<br />

Separate Iterator-Klasse<br />

• Neu definierte Iterator-Klasse itk<br />

• Kann durchaus im normalen<br />

Codeblock dynamisch erfolgen<br />

• Instanz der Klasse initialisieren und<br />

zurückgeben<br />

Bewertung<br />

• Etwas komplexer zu realisieren<br />

• Erlaubt parallele Iteration<br />

• Ändern des Objekts während der<br />

Iteration erlaubt, da Kopie erstellt<br />

wurde<br />

• Kopie erstellen bewusste<br />

Entscheidung<br />

1 class Iterklasse(object):<br />

2 def __init__(self):<br />

3 self.lis = [1,2,3]<br />

4 def __iter__(self):<br />

5 class itk(object):<br />

6 def __init__(self, lis):<br />

7 self.index = 0<br />

8 self.lis = lis[:]<br />

9 def next(self):<br />

10 if self.index >= len(self.lis):<br />

11 raise StopIteration<br />

12 self.index += 1<br />

13 return self.lis[self.index-1]<br />

14 return itk(self.lis)<br />

1 >>> itc = Iterklasse()<br />

2 >>> it1, it2 = iter(itc), iter(itc)<br />

3 >>> it1.next(), it2.next()<br />

4 (1, 1)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 234 / 326


<strong>Programmieren</strong> in Python<br />

Objektorientierung<br />

Iteratoren für eigene Klassen – Iterator von Standardtyp<br />

Iterator von Standardtyp verwenden<br />

• Standardtyp nehmen oder aufbauen<br />

• Davon Iterator zurückgeben<br />

Bewertung<br />

• Einfach, robust; bevorzugen<br />

in Tests<br />

• Sobald Iterator implementiert ist, ist<br />

auch automatisch der in-Operator<br />

realisiert<br />

• Iteriert über alle Element und<br />

vergleicht<br />

• Bessere Implementierung darf man<br />

angeben<br />

1 class Iterstd(object):<br />

2 def __init__(self):<br />

3 self.lis = [1, 2, 3]<br />

4 def __iter__(self):<br />

5 return iter(self.lis)<br />

1 >>> its = Iterstd()<br />

2 >>> it1, it2 = iter(its), iter(its)<br />

3 >>> it1.next(), it2.next()<br />

4 (1, 1)<br />

1 >>> its = Iterstd()<br />

2 >>> 3 in its, 17 in its<br />

3 (True, False)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 235 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Motivation<br />

Iteratoren – Umsetzungskonzept<br />

• Iterator: Zwischen jedem next<br />

Anwendungscode ausführen<br />

• Iteratorklasse: Zustand halten und bei<br />

jedem next aktualisieren<br />

• Statt Iteratorklasse?: Einfache Schleife<br />

klappt nicht; man kann Ausführung<br />

nicht anhalten und Anwendungscode<br />

ausführen<br />

Lösungsansätze<br />

• Man kann den Anwendungscode, den<br />

man für jedes Objekt ausführen will<br />

“mitgeben”: Funktionales<br />

<strong>Programmieren</strong><br />

• Man kann die Schleife doch anhalten;<br />

Generatoren<br />

1 i = 0<br />

2 def naechstes():<br />

3 global i<br />

4 if i >= len(lis):<br />

5 raise StopIteration<br />

6 ele = lis[i]<br />

7 i += 1<br />

8 return ele<br />

1 for ele in lis:<br />

2 # naechstes ele, Anwendungscode?<br />

3 pass<br />

1 def f(x):<br />

2 pass # Anwendungscode<br />

3 ###<br />

4 map(f, lis)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 236 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Konzept<br />

Generatoren in Python<br />

• yield statt return in Funktion<br />

• Nur eins von beiden in Funktion<br />

• Bei Funktionsaufruf wird automatisch<br />

Generatorobjekt erzeugt, das sich wie<br />

Iterator verhält<br />

• Bei next wird Wert bei yield<br />

zurückgegeben und Ausführung<br />

eingefroren<br />

• Bei jedem next zum nächsten Wert<br />

• StopIteration am Ende<br />

Vorteile<br />

• Keine großen Datenstrukturen im<br />

Speicher halten<br />

• Natürliche Realisierung von Iteratoren<br />

• Grundlage für die meisten Builtins<br />

quads.py<br />

1 def quads():<br />

2 i = 1<br />

3 while True:<br />

4 yield i**2<br />

5 i += 1<br />

1 >>> q = quads()<br />

2 >>> q.next()<br />

3 1<br />

4 >>> q.next()<br />

5 4<br />

6 >>> q.next()<br />

7 9<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 237 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Grundlage für viele Builtins<br />

Beispiel: Eine offene Datei ist ein<br />

Generator, der die Zeilen in der Datei<br />

sukkzesive zurückgibt<br />

1 >>> f = file("quads.py"); f<br />

2 <br />

4 >>> f.next()<br />

5 ’def quads():\n’<br />

6 >>> f.next()<br />

7 ’ i = 1\n’<br />

8 ....<br />

9 >>> f.next()<br />

0 ’ i += 1\n’<br />

1 >>> f.next()<br />

2 StopIteration<br />

Beispiel: Das Ergebnis eines Aufrufs von<br />

reversed ist ein Generator, der die<br />

Elemente rückwärts aufzählt<br />

1 >>> lis = [1, 2, 3]<br />

2 >>> g = reversed(lis); g<br />

3 <br />

5 >>> g.next()<br />

6 3<br />

7 >>> g.next()<br />

8 2<br />

9 >>> g.next()<br />

10 1<br />

11 >>> g.next()<br />

12 StopIteration<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 238 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Verwendung und weitere Beispiele<br />

Verwendung<br />

• Summe der Quadratzahlen, die zum<br />

ersten Mal 1.000.000 erreicht<br />

nquads<br />

• quads war unendlich, beschränkt geht<br />

auch<br />

• Mit list wird wieder eine Liste daraus,<br />

läuft ewig für unendliche Generatoren<br />

• Verwendung von for möglich und<br />

sinnvoll auch bei potentiell unendlich<br />

lange laufenden Generatoren<br />

• Abbruch mit StopIteration<br />

• Abbruch nicht notwendig<br />

1 def hoch4():<br />

2 for ele in quads():<br />

3 yield ele**2<br />

1 sum = 0<br />

2 for quad in quads():<br />

3 sum += quad<br />

4 if sum > 1000000:<br />

5 break<br />

6 print sum # 1005720<br />

1 def nquads(n):<br />

2 for i in range(1, n+1):<br />

3 yield i**2<br />

1 def nquads(n):<br />

2 grenze = n**2<br />

3 for ele in quads():<br />

4 yield ele<br />

5 if ele >= grenze:<br />

6 raise StopIteration<br />

>>> list(nquads(10))<br />

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 239 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Fibonacci<br />

Folge der Fibonacci-Zahlen<br />

• Startwerte, zwei Mal die Eins<br />

• Die nächste Fibonacci-Zahl ist die<br />

Summe der beiden Vorherigen<br />

Umsetzung<br />

• Aktuelle und vorletzte Fibonacci-Zahl<br />

halten<br />

• Vorletzte zurück geben und dabei<br />

Zustand einfrieren<br />

Verwendung<br />

• Die ersten 10 Fibonacci-Zahlen<br />

1 def fib():<br />

2 fn0, fn1 = 1, 1<br />

3 while True:<br />

4 fn0, fn1, fn2 = fn0+fn1, fn0, fn1<br />

5 yield fn2<br />

1 >>> f = fib()<br />

2 >>> for i in range(10):<br />

3 print f.next(),<br />

4 1 1 2 3 5 8 13 21 34 55<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 240 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Baum traversieren<br />

Baum<br />

• Knoten als Drei-Tupel, Wert ist String<br />

• Iterator für In-Order normalerweise<br />

aufwendig, Warteschlange<br />

Baum traversieren mit Generatoren<br />

• Natürliche Formulierung<br />

• Nutzen von Schleifen mit neuen<br />

Generatoren im rekursiven Abstieg<br />

bintree<br />

b<br />

a<br />

c<br />

1 def inorder(node):<br />

2 if node == None:<br />

3 raise StopIteration<br />

4 left, value, right = node<br />

5 for valueleft in inorder(left):<br />

6 yield valueleft<br />

7 yield value<br />

8 for valueright in inorder(right):<br />

9 yield valueright<br />

1 bintree = (<br />

2 ((None, "d", None),<br />

3 "b",<br />

4 (None, "e", None)),<br />

5 "a",<br />

6 (None, "c", None))<br />

d<br />

e<br />

1 >>> for value in inorder(bintree):<br />

2 print value,<br />

3 d b e a c<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 241 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – itertools, Slicen<br />

Generatoren sind keine Sequenzen<br />

• Generatoren sind potentiell unendlich<br />

• Umformung in Listen und Slicing nicht<br />

sinnvoll<br />

• Standard-Features von Sequenzen<br />

(Slicing, Syntax) nicht verfügbar<br />

Modul itertools<br />

• Wichtigste Funktionalität von<br />

Sequenzen für Generatoren zur<br />

Verfügung stellen<br />

• Slicen, Funktional <strong>Programmieren</strong><br />

1 >>> list(quads())<br />

2 ... # 1 GB, 2 GB, 3 GB, ...<br />

3 ... # ca. 3 Minuten auf 32 Bit-Rechner<br />

4 MemoryError<br />

islice(<br />

[, ], [, ])<br />

1 >>> from itertools import islice<br />

2 >>> q = quads()<br />

3 >>> i = islice(q, 0, 10)<br />

4 >>> i.next(), i.next(), i.next()<br />

5 1, 4, 9<br />

6 >>> list(i)<br />

7 [16, 25, 36, 49, 64, 81, 100]<br />

Slicen mit islice<br />

8 >>> list(islice(q, 0, 10))<br />

9 [121, 144, 169, 196, 225, 256, 289, 324,<br />

• Aufruf von islice mit start, stop, step<br />

10 >>> list(islice(q, 0, 10))<br />

• Nachbau Funktionalität<br />

[start:stop:step]<br />

11<br />

12<br />

[441, 484, 529, 576, 625, 676, 729, 784,<br />

>>> list(islice(quads(), 0, 10))<br />

13 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 242 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – itertools, Funktional Progammieren<br />

Funktional <strong>Programmieren</strong><br />

• Etwas für alle Elemente einer<br />

Liste tun<br />

• Potentiell problematisch bei<br />

unendlichen Listen<br />

Spezielle Primitive für Generatoren<br />

• Primitive mit i am Anfang*,<br />

imap, ifilter, izip<br />

• Im Modul itertools<br />

• Geben Generatoren zurück<br />

• Gleiche Funktionalität wie<br />

funktionale Primitive, nur<br />

sukkzesive<br />

1 >>> from itertools import islice, imap,<br />

2 ifilter, izip<br />

3 >>> [i for i in islice(quads(), 0, 20)<br />

4 if i%2==0]<br />

5 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />

6 >>> list(islice(ifilter(lambda x: x%2 == 0,<br />

7 quads()), 0, 10))<br />

8 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />

9 >>> gen = ifilter(lambda x: x%2 == 0, quads())<br />

10 >>> gen<br />

11 <br />

12 >>> gen.next()<br />

13 4<br />

14 >>> gen.next(),gen.next(),gen.next(),gen.next()<br />

15 (16, 36, 64, 100)<br />

16 >>> import math<br />

17 >>> list(islice(imap(math.sqrt, quads()), 9))<br />

* Keine Assoziation zu Apple-Produkten,<br />

18 [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]<br />

geht auf allen Rechnern, patent pending... :-)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 243 / 326


<strong>Programmieren</strong> in Python<br />

Generatoren<br />

Generatoren – Generator Expressions<br />

List Comprehension für<br />

Generatoren<br />

• List Comprehension direkt<br />

wieder nicht sinnvoll, da<br />

potentiell unendlich<br />

7 (1, 4, 9)<br />

• Ausdruck mit runden Klammern<br />

8 >>> list(gq)<br />

() statt eckigen Klammern []<br />

9 [16, 25, 36, 49, 64, 81]<br />

• Erzeugt dann Generator/Iterator 10 >>> gquads = (i for i in quads() if i%2 == 0)<br />

Mächtiges elegantes Konzept,<br />

nutzen!<br />

1 >>> gq = (i**2 for i in range(10))<br />

2 >>> gq<br />

3 <br />

4 >>> gq.next()<br />

5 0<br />

6 >>> gq.next(), gq.next(), gq.next()<br />

11 >>> gquads<br />

12 <br />

13 >>> gquads.next()<br />

14 4<br />

15 >>> gquads.next(),gquads.next(),gquads.next()<br />

16 (16, 36, 64)<br />

17 >>> from itertools import islice<br />

18 >>> list(islice((i for i in quads() if i%2==0)<br />

19 ,0,10))<br />

20 [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 244 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen<br />

Ausnahmen – spezieller Kontrollfluss<br />

• Fokus auf Fehlerbehandlung<br />

• Erlaubt saubere Trennung von funktionalen Bestandteilen und “Rest” wie<br />

Fehlerbehandlung und Spezialfällen<br />

• Sollte nicht für allgemeinen Kontrollfluss verwendet werden<br />

Ausnahmen in Python<br />

• In Sprache integriert, einfach zu verwenden<br />

• Ähnlich zu Java<br />

Syntax<br />

• try, else, except, finally: Rahmen für Code-Strecken mit potentiellen<br />

Ausnahmen, Fangen und Verarbeiten der Ausnahmen<br />

• raise: Werfen von Ausnahmen<br />

• assert: Wie in C<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 245 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen fangen – Schema<br />

• im try-Block ausführen<br />

• Falls Ausführung Ausnahme wirft mit<br />

expect fangen<br />

• Eine oder mehrere Ausnahmen als<br />

Tupel möglich<br />

• Mehrere except möglich<br />

• Mit optionalem an Ausnahme-Instanz<br />

an binden<br />

• Falls Ausnahme gefangen<br />

entsprechenden except-Block<br />

ausführen<br />

• else-Block (optional) falls keine<br />

Ausnahme geworfen wurde<br />

• finally-Block (optional) immer, ob<br />

Ausnahme geworfen wurde (und<br />

gefangen wurde oder nicht) oder nicht<br />

try:<br />

<br />

except :<br />

<br />

except ([, ]*):<br />

<br />

except as :<br />

<br />

else:<br />

<br />

finally:<br />

<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 246 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen fangen – Beispiele, except, else<br />

1 >>> 3/0<br />

2 ZeroDivisionError: integer div.. by zero2 3/0<br />

3 >>> try:<br />

4 3/0<br />

5 except ZeroDivisionError:<br />

6 print "nicht durch Null"<br />

7 nicht durch Null<br />

8 >>> try:<br />

9 3/0<br />

0 except ZeroDivisionError as e:<br />

1 print type(e), e<br />

2 <br />

3 integer division or modulo by zero<br />

4 >>> try:<br />

5 3/0<br />

6 except IndexError:<br />

7 print "IE"<br />

8 except ZeroDivisionError:<br />

9 print "ZDE"<br />

0 ZDE<br />

1 >>> try:<br />

3 except ZeroDivisionError:<br />

4 print "ZDE"<br />

5 else:<br />

6 print "OK"<br />

7 ZDE<br />

8 >>> try:<br />

9 3/1<br />

10 except ZeroDivisionError:<br />

11 print "ZDE"<br />

12 else:<br />

13 print "OK"<br />

14 3<br />

15 OK<br />

ZeroDivisionError, builtin Ausnahmetyp<br />

Nicht gefangene Ausnahme propagiert<br />

zum TopLevel<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 247 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen fangen – Beispiele, finally<br />

1 >> try:<br />

2 ... 3/0<br />

3 ... except ZeroDivisionError:<br />

4 ... print "ZDE"<br />

5 ... finally:<br />

6 ... print "immer"<br />

7 ...<br />

8 ZDE<br />

9 immer<br />

0 >>> try:<br />

1 ... 3/1<br />

2 ... except ZeroDivisionError:<br />

3 ... print "ZDE"<br />

4 ... finally:<br />

5 ... print "immer"<br />

6 ...<br />

7 3<br />

8 immer<br />

1 >>> try:<br />

2 ... 3/0<br />

3 ... except IndexError:<br />

4 ... print "IE"<br />

5 ... finally:<br />

6 ... print "immer"<br />

7 ...<br />

8 immer<br />

9 ZeroDivisionError: integer division<br />

10 or modulo by zero<br />

finally wird immer ausgeführt<br />

Beinhaltet meist Aufräumaktionen<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 248 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen fangen – Datei-Beispiel<br />

Mit Ausnahmen arbeiten<br />

• Code unter der Annahme schreiben,<br />

dass alles funktioniert<br />

•<br />

5<br />

Ausnahme und Behandlung bei Fehler<br />

count += 1<br />

6 except IOError:<br />

Mit Dateien arbeiten<br />

7 count = 0<br />

• Zähle Zeilen in Datei<br />

8 return count<br />

• 0, wenn Datei nicht vorhanden<br />

1 def countlinesfile(filename):<br />

2 try:<br />

3 count = 0<br />

4 for _ in file(filename):<br />

1 >>> countlinesfile("/etc/passwd")<br />

2 44<br />

3 >>> countlinesfile("/GIBTESNICHT")<br />

4 0<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 249 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmeklassen – Exception, Hierarchie<br />

1 BaseException<br />

2 +-- SystemExit<br />

3 +-- KeyboardInterrupt<br />

4 +-- GeneratorExit<br />

5 +-- Exception<br />

6 +-- StopIteration<br />

7 +-- StandardError<br />

8 | +-- BufferError<br />

9 | +-- ArithmeticError<br />

0 | | +-- FloatingPointError<br />

1 | | +-- OverflowError<br />

2 | | +-- ZeroDivisionError<br />

3 | +-- AssertionError<br />

4 | +-- AttributeError<br />

5 | +-- EnvironmentError<br />

6 | | +-- IOError<br />

7 | | +-- OSError<br />

8 | | +-- WindowsError (Windows)<br />

9 | | +-- VMSError (VMS)<br />

0 | +-- EOFError<br />

1 | +-- ImportError<br />

2 | +-- LookupError<br />

3 | | +-- IndexError<br />

4 | | +-- KeyError<br />

5 | +-- MemoryError<br />

6 | +-- NameError<br />

7 | | +-- UnboundLocalError<br />

1 | +-- ReferenceError<br />

2 | +-- RuntimeError<br />

3 | | +-- NotImplementedError<br />

4 | +-- SyntaxError<br />

5 | | +-- IndentationError<br />

6 | | +-- TabError<br />

7 | +-- SystemError<br />

8 | +-- TypeError<br />

9 | +-- ValueError<br />

10 | +-- UnicodeError<br />

11 | +-- UnicodeDecodeError<br />

12 | +-- UnicodeEncodeError<br />

13 | +-- UnicodeTranslateError<br />

14 +-- Warning<br />

15 +-- DeprecationWarning<br />

16 +-- PendingDeprecationWarning<br />

17 +-- RuntimeWarning<br />

18 +-- SyntaxWarning<br />

19 +-- UserWarning<br />

20 +-- FutureWarning<br />

21 +-- ImportWarning<br />

22 +-- UnicodeWarning<br />

23 +-- BytesWarning<br />

Eigene Ausnahmeklassen passend<br />

ableiten<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 250 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen werfen<br />

Ausnahmen werfen mit raise<br />

• raise : Wirft Ausnahme der<br />

Klasse , muss von<br />

BaseException erben<br />

• raise : Wirft Ausnahme der<br />

Instanz , muss Instanz von<br />

BaseException ein<br />

Instanzen oder Klassen werfen<br />

• Instanz um Daten mitzugeben<br />

• Häufig sind Daten ein String<br />

Vordefinierte Ausnahmen verwendbar<br />

1 >>> raise Exception("nix geht")<br />

2 Exception: nix geht<br />

1 >>> class MeineAusnahme(object):<br />

2 pass<br />

3 >>> raise MeineAusnahme<br />

4 TypeError: exceptions must be old-style<br />

5 classes or derived from<br />

6 BaseException, not type<br />

7<br />

8 >>> class MeineAusnahme(Exception):<br />

9 pass<br />

10 >>> raise MeineAusnahme<br />

11 __main__.MeineAusnahme<br />

12<br />

13 >>> try:<br />

14 msg="Weil es nicht geht"<br />

15 raise MeineAusnahme(msg)<br />

16 except MeineAusnahme as inst:<br />

17 print "Warum?", inst<br />

18 Warum? Weil es nicht geht<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 251 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen mit assert<br />

Zusicherungen mit assert<br />

• : ein Test<br />

• Sobald Test äquivalent zu False<br />

evaluiert, AssertionError<br />

Optimierung<br />

• Gesteuert durch globale Variable<br />

__debug__<br />

assert , <br />

if __debug__:<br />

if not :<br />

raise AssertionError()<br />

• Beim Übersetzen mit -O wird<br />

__debug__ = False gesetzt bzw. der<br />

Bytecode komplett entfernt<br />

Benutzung<br />

• Schleifeninvarianten, Vor- und<br />

Nachbedingungen<br />

• Frühzeitige Fehlererkennung<br />

• Lauffähige Dokumentation<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 252 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen mit assert – Beispiel<br />

Zerlegen von einem String<br />

• Wir gehen davon aus, dass der String<br />

immer genau einen Doppelpunkt<br />

enthält<br />

• Was passiert im Fehlerfall?<br />

Defensiv programmieren<br />

• Früh fehlschlagen, statt erst mal weiter<br />

machen; assert<br />

• Fehlermeldungen werden besser<br />

1 def zerlege_nonsafe(s):<br />

2 l = s.split(":")<br />

3 return (l[0], l[1])<br />

4 def zerlege_safe(s):<br />

5 l = s.split(":")<br />

6 assert len(l) == 2, l<br />

7 return (l[0], l[1])<br />

1 >>> zerlege_nonsafe("a:b:c")<br />

2 (’a’, ’b’)<br />

3 >>> zerlege_safe("a:b:c")<br />

4 assert len(l) == 2, l<br />

5 AssertionError: [’a’, ’b’, ’c’]<br />

6 >>> zerlege_nonsafe("a")<br />

7 return (l[0], l[1])<br />

8 IndexError: list index out of range<br />

9 >>> zerlege_safe("a")<br />

10 assert len(l) == 2, l<br />

11 AssertionError: [’a’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 253 / 326


<strong>Programmieren</strong> in Python<br />

Ausnahmen<br />

Ausnahmen statt “Check then Act”-Fehler<br />

Aufgabe<br />

• Überprüfe die Existenz einer Datei<br />

• Falls vorhanden, erste Zeile zurück<br />

• Falls nicht vorhanden, hart beenden<br />

• Es darf kein IOError geworfen werden<br />

Ansätze<br />

• “Check then act”, fehlerhaft<br />

• Es kann passieren, dass jemand<br />

zwischen Check Zeile 4 und<br />

verwenden, die Datei entfernt<br />

• Es wird dann doch IOError geworfen<br />

• Mach es; melde, wenn es nicht geht<br />

• Kein Problem, sobald die Datei<br />

geöffnet werden konnte, ist sie da<br />

Ein IOError wäre natürlich doch die<br />

bessere Variante, statt hart zu beenden<br />

1 def get_status(fname):<br />

2 if not os.path.exists(fname):<br />

3 print "file not found"<br />

4 sys.exit(-1)<br />

5 return file(fname).readline()<br />

1 def get_status(fname):<br />

2 try:<br />

3 return file(fname).readline()<br />

4 except (IOError, OSError) as e:<br />

5 print "problem; exiting: "+str(e)<br />

6 sys.exit(-1)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 254 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Bibliotheken – Module in der Standardbibliothek<br />

Python-Bibliotheken – viel im Standard<br />

• Als Module/Pakete verfügbar<br />

• Breites Angebot, “Batteries included”,<br />

ausführlich dokumentiert<br />

Beispiele:<br />

• os: Systemnah, Verzeichnisse/Dateien<br />

sys: Python-Umgebung<br />

• unittest: Unit Testing<br />

pickle: Objektpersistenz<br />

urllib, cgi, imap, ftp, http: Web,<br />

Internet Protokolle<br />

PIL: Bildbearbeitung (nicht standard)<br />

turtle: Einfachstgraphik, Tkinter<br />

Tkinter, wx, qt: GUI, alle OS<br />

pygame: Spielend Spiele spielen<br />

re: Reguläre Ausdrücke<br />

1 >>> import os<br />

2 >>> os.getcwd()<br />

3 ’/home/mi/ssinn001’<br />

4 >>> os.chdir("/usr/share/games/fortunes")<br />

5 >>> os.getcwd()<br />

6 ’/usr/share/games/fortunes’<br />

7 >>> [x for x in os.listdir(os.getcwd())<br />

8 if x.endswith(".dat")]<br />

9 [’fortunes.dat’, ’riddles.dat’,<br />

10 ’literature.dat’]<br />

11 >>> import sys<br />

12 >>> sys.argv<br />

13 [’’]<br />

14 >>> import re<br />

15 >>> re.findall(r’ab+c’, "abbcdsabcab")<br />

16 [’abbc’, ’abc’]<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 255 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Unit Testing<br />

Ziel<br />

• Funktionalitäten feingranular testen<br />

• Automatisierung, einfache Verwaltung<br />

von Testfällen<br />

Umsetzung – unittest, Verwendung<br />

• Anlehnung an JUnit<br />

• Von Klasse TestCase erben<br />

• Testfunktionen mit test_ am Anfang<br />

des Namens<br />

• Zusicherung, self.: Erwartet<br />

• assert_: True, wie assert<br />

• assertEqual: Zwei gleich Parameter<br />

• assertRaises: Passende Ausnahme<br />

• setUp, tearDown: Vor/nach jedem Test,<br />

Test Fixture<br />

• Aufrufen mit unittest.main()<br />

import unittest<br />

class (unittest.TestCase):<br />

[def setUp(self):<br />

]<br />

...<br />

[def tearDown(self):<br />

]<br />

...<br />

[def test(self):<br />

...<br />

[self.assert_() |<br />

[self.assertEqual(, ) |<br />

[self.assertRaises()]*<br />

...<br />

]*<br />

if __name__ == ’__main__’:<br />

unittest.main()<br />

Anpassbar, flexibel, weitere Optionen<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 256 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Unit Testing – Beispiel<br />

Beispieltest “Ist Primzahl?”<br />

• Importieren Modul<br />

• Zu testende Funktion is_prim,<br />

meist in anderem Modul<br />

• Testfunktionen<br />

• Start der Tests<br />

Ausgabe<br />

..<br />

• Zwei Tests ok durchgelaufen<br />

-------------------------------<br />

Ran 2 tests in 0.000s<br />

OK<br />

1 import unittest<br />

2<br />

3 def is_prim(x):<br />

4 if x < 2: return False<br />

5 ts = [t for t in range(2, x) if x%t==0]<br />

6 return not ts<br />

7<br />

8 class PrimTest(unittest.TestCase):<br />

9 def setUp(self):<br />

10 self.r = range(1, 101) # 1..100<br />

11 self.ps = 25 # 25 Primzahlen<br />

12 def testPrim1(self):<br />

13 self.assert_(is_prim(2))<br />

14 self.assert_(not is_prim(4))<br />

15 self.assertEqual(is_prim(7), True)<br />

16 def testPrim2(self):<br />

17 prims = filter(is_prim, self.r)<br />

18 self.assertEqual(len(prims), self.ps)<br />

19 if __name__ == ’__main__’:<br />

20 unittest.main()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 257 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Pickle – Einfache Objektpersistenz<br />

Ziel<br />

• Serialisierung von Objektinstanzen<br />

• Plattform- und versionsunabhängig<br />

• Kein Persistenzframework<br />

Umsetzung – pickle<br />

• Für eingebaute Standardtypen<br />

• Hierarchien und Referenzen<br />

• Klassen, aber nur Instanzen<br />

Beispiel<br />

• Schreiben mit dump<br />

• Lesen mit load<br />

Aclass.py<br />

1 class A(object):<br />

2 def __init__(self, end=3):<br />

3 self.lis = range(1, end)<br />

4 def __str__(self):<br />

5 return "A["+str(self.lis)+"]"<br />

6 __repr__ = __str__<br />

1 import pickle<br />

2 import Aclass<br />

3<br />

4 tup=(1, 1.0, 1+1j, (1,), "1", {1:2})<br />

5 lis=[1,2,3]<br />

6 lis.append(lis)<br />

7 alis=[Aclass.A(i) for i in range(1, 6)]<br />

8 pickle.dump((tup, lis),<br />

9 file("tuplis.pickle", "wb"))<br />

10 pickle.dump(alis,<br />

11 file("alis.pickle", "wb"))<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 258 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Pickle – Einlesen<br />

Beispiel<br />

• Referenzen, auch zirkuläre,<br />

werden richtig wiederhergestellt<br />

• Instanzen von Objekten werden<br />

richtig wieder instanziiert<br />

• Klasse/Modul muss verfügbar<br />

sein, wird nicht gepickelt<br />

• Einladen über import muss<br />

klappen<br />

Erweiterungen<br />

• Pickeln von Instanzen über<br />

Methoden beeinflussbar<br />

• Pickeln von Klassen oder<br />

Funktionen nicht möglich<br />

• cPickle, schneller<br />

• Unterschiedliche<br />

Protokollversionen<br />

1 >>> import pickle<br />

2 >>> f = file("tuplis.pickle", "rb")<br />

3 >>> t, l = pickle.load(f)<br />

4 >>> t<br />

5 (1, 1.0, (1+1j), (1,), ’1’, {’1’: ’eins’})<br />

6 >>> l<br />

7 [1, 2, 3, [...]]<br />

8 >>> al = pickle.load(file("alis.pickle","rb"))<br />

9 >>> al<br />

10 [A[[]], A[[1]], A[[1, 2]], A[[1, 2, 3]],<br />

11 A[[1, 2, 3, 4]]]<br />

12 >>> al[0].__class__<br />

13 <br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 259 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Internetdaten verarbeiten<br />

• rfc822, mimetools, mimetypes, mailcap, imaplib, mailbox, smtplib, nntplib:<br />

Email- und News-spezifische Bibliotheken<br />

• uu, binascii: Konvertierungen<br />

• SocketServer, SimpleHTTPServer, ftplib: Protokollimplementierungen<br />

• urllib, urllib2, urlparse: URL-Manipulation, Anfragen<br />

1 >>> import urllib2, re<br />

2 >>> s = urllib2.urlopen("http://www.heise.de/newsticker/").read()<br />

3 >>> s[:100]<br />

4 ’\n\n\n\n \n<br />

5 \n\n 7-Tage-News | heise online\n\n ’<br />

6 >>> hl = re.findall(r’(.*?)’, s)<br />

7 >>> for t in [t for t in hl if "Android" in t]: print t<br />

8 Unzuverlaessige Trojaner-Warnungen durch Android 4.2<br />

9 LTE-Smartphone mit Android 4.0 von HTC<br />

0 Java-IDE IDEA 12: neue Oberflaeche, neuer Compiler-Modus, neuer Android-Designer<br />

1 Gingerbread bleibt die am meisten benutzte Android-Version<br />

2 Aktualisierte Maps-API fuer Android-Entwickler<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 260 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Turtle Graphics<br />

Turtle Graphics<br />

• Einfache Graphiken wie mit einem Stift<br />

erstellen, “Logo, Programming for<br />

Kids”<br />

• Zeichenfläche mit Mitte 0,0<br />

• Kommandos up (Stift hoch), down (Stift<br />

auf Papier), goto (Bewege Stift), . . .<br />

1 from turtle import *<br />

2 down()<br />

3 goto(100, 0)<br />

4 goto(0, -100)<br />

5 goto(100, -100)<br />

6 up()<br />

7 goto(0, 0)<br />

8 down()<br />

9 for i in range(100):<br />

0 goto(i, i**2/100.)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 261 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Bildbearbeitung mit PIL<br />

Python Imaging Library (PIL)<br />

• C-Erweiterung<br />

• Nicht im Standard<br />

• Einfach, mächtig<br />

• ([noch] nur Python 2.x)<br />

1 >>> import Image<br />

2 >>> im=Image.open("lena.png")<br />

3 >>> im.show()<br />

4 >>> im2=im.resize(map(lambda x: x*2,<br />

5 im.size))<br />

6 >>> im2.show()<br />

7 >>> im3=im.rotate(45)<br />

8 >>> im3.show()<br />

9 >>> import ImageFilter<br />

0 >>> im4=im.filter(ImageFilter.FIND_EDGES)<br />

1 >>> im4.show()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 262 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

Spiele mit pygame<br />

Spiele <strong>Programmieren</strong> mit pygame<br />

• Kombination von Bibliotheken<br />

• 2D/3D-Grafik, Sound, . . .<br />

• Abstraktionen (Sprites, Kollision)<br />

Beispiel<br />

• Viele, viele Logos<br />

1 import sys, pygame<br />

2<br />

3 pygame.init()<br />

4 bild = pygame.image.load("hsrm.png")<br />

5 groesse = breite, hoehe = 800, 600<br />

1 if __name__ == ’__main__’:<br />

2 main()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 263 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

pygame – Ein Bild bewegt sich<br />

Bewegung: bewege<br />

• Innerhalb eines Rechtecks<br />

• Bei Wand (Ende Rechteck),<br />

ändere Bewegungsrichtung<br />

(wieder zurück)<br />

• Bewege!<br />

Anzeige, Animation: main<br />

• Initialisierung Bildschirm,<br />

Bewegungsrichtung<br />

• GameLoop<br />

• Bearbeite (ignoriere) Events<br />

• Hintergrund<br />

• Bewege Bild<br />

• Bild auf (virtuellen) Bildschirm<br />

• Bringe vorbereiteten<br />

(flackerfreien) Bildschirm zur<br />

Ansicht<br />

1 def bewege(rect, direction):<br />

2 if rect.left < 0 or rect.right > breite:<br />

3 direction[0] = -direction[0]<br />

4 if rect.top < 0 or rect.bottom > hoehe:<br />

5 direction[1] = -direction[1]<br />

6 return rect.move(direction)<br />

7<br />

8 def main():<br />

9 screen = pygame.display.set_mode(groesse)<br />

10 bild_rect = bild.get_rect()<br />

11 direction = [1,1] # bewegungsrichtung<br />

12 while True:<br />

13 for event in pygame.event.get():<br />

14 if event.type == pygame.QUIT:<br />

15 sys.exit()<br />

16 screen.fill((50, 130, 40)) # gruen<br />

17 bild_rect = bewege(bild_rect, direction)<br />

18 screen.blit(bild, bild_rect)<br />

19 pygame.display.flip()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 264 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

pygame – Besser, Klasse für Spielobjekte<br />

Logo-Klasse<br />

• Spielobjekt, Bild parametrisiert<br />

• Taucht zufällig intial irgendwo<br />

auf<br />

• Bewegt sich bei<br />

Richtungsänderung an einer<br />

Wand zufällig (1–3) anders<br />

schnell weiter<br />

• Kann sich selbst zeichnen<br />

Logos, die verwendet werden<br />

• hsrm.png<br />

• hsrml.png<br />

• pygame.png<br />

1 class Logo(object):<br />

2 def __init__(self,screen,fname="hsrm.png"):<br />

3 self.screen = screen<br />

4 self.bild = pygame.image.load(fname)<br />

5 r = self.rect = self.bild.get_rect()<br />

6 r.left=random.randint(0,breite-r.width)<br />

7 r.top=random.randint(0,hoehe-r.height)<br />

8 self.dir = [random.randint(1,3),<br />

9 random.randint(1,3)]<br />

10 def bewege(self):<br />

11 if self.rect.left < 0:<br />

12 self.dir[0] = random.randint(1, 3)<br />

13 elif self.rect.right > breite:<br />

14 self.dir[0] = -random.randint(1, 3)<br />

15 if self.rect.top < 0:<br />

16 self.dir[1] = random.randint(1, 3)<br />

17 elif self.rect.bottom > hoehe:<br />

18 self.dir[1] = -random.randint(1, 3)<br />

19 self.rect = self.rect.move(self.dir)<br />

20 self.screen.blit(self.bild, self.rect)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 265 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

pygame – Besser, Loop<br />

Game Loop, feste Framerate<br />

• Frames per Second (FPS)<br />

• Setzen mit clock.tick(FPS),<br />

• wartet/schläft gegebenenfalls<br />

Neues Feature<br />

• Neues Objekt bei jedem Klick<br />

(Maus loslassen)<br />

• Grosses Logo<br />

Position setzen<br />

class Logo(object): ...<br />

1 def setpos(self, pos):<br />

2 self.rect.left = pos[0]<br />

3 self.rect.top = pos[1]<br />

1 def main():<br />

2 screen=pygame.display.set_mode(groesse)<br />

3 clock=pygame.time.Clock()<br />

4 logos=[Logo(screen) for i in range(17)]<br />

5 while True:<br />

6 clock.tick(60)<br />

7 for event in pygame.event.get():<br />

8 if event.type == pygame.QUIT:<br />

9 sys.exit()<br />

10 if event.type == pygame.MOUSEBUTTONUP:<br />

11 if event.button == 1:<br />

12 logo=Logo(screen,"hsrml.png")<br />

13 logo.setpos(event.pos)<br />

14 logos.append(logo)<br />

15 screen.fill((50,130,40))<br />

16 for logo in logos:<br />

17 logo.bewege()<br />

18 pygame.display.flip()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 266 / 326


<strong>Programmieren</strong> in Python<br />

Bibliotheken<br />

pygame – Mehr, Kollisionserkennung<br />

Kollisionserkennung<br />

• Wann berühren sich zwei<br />

Objekte<br />

• In pygame geschenkt<br />

Code-Änderung<br />

• Global merken, welche Objekte<br />

es gibt<br />

• Prüfen ob Kollision, wenn ja,<br />

dann alternatives Bild<br />

• Kollisionserkennung vieler<br />

Objekte hier naiv (quadratisch)<br />

• Bewegen über alle Objekte<br />

1 class Logo(object):<br />

2 logos = []<br />

3 def __init__(self, ...):<br />

4 ...<br />

5 self.alt_bild=pygame.image.load("pygame.p<br />

6 Logo.logos.append(self)<br />

7 def bewege(self):<br />

8 ...<br />

9 bild = self.alt_bild<br />

10 if self._collides_with()<br />

11 else self.bild<br />

12 self.screen.blit(bild, self.rect)<br />

13 def _collides_with(self):<br />

14 return [logo for logo in Logo.logos<br />

15 if logo != self<br />

16 if self.rect.colliderect(logo.rect)]<br />

17 def main():<br />

18 ...<br />

19 for logo in Logo.logos:<br />

20 ...<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 267 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Reguläre Ausdrücke<br />

Reguläre Ausdrücke<br />

• “Matchen”, finde passenden String<br />

• Flexibles Matchen auf “Pattern” mit Sonderzeichen<br />

• Erweiterte reguläre Ausdrücke, nicht Wildcards<br />

• In Java, Python, . . . verfügbar, Kommandozeile mit egrep<br />

Reguläre Ausdrücke in <strong>Skript</strong>sprachen<br />

• Spezielle Bibliotheken (Python, PHP, Java) oder Teil der Sprache (Perl, awk)<br />

• Kompilation des Patterns, Ausführen auf C-basierter Engine<br />

Einsatz<br />

• Stringverarbeitung, Extraktion, Suchen/Ersetzen<br />

• Test auf syntaktische Korrektheit (Email-Adresse, Telefonnummer)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 268 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Matchen mit einfachen Patterns<br />

Teil des Strings<br />

• Ein Pattern beschreibt einen Teil des<br />

zu durchsuchenden Strings<br />

Pattern – Zeichen matchen sich selbst<br />

• Zum Beispiel matcht das Pattern fahr<br />

den String erfahren<br />

Groß- und Kleinschreibung wird<br />

unterschieden<br />

• Das Pattern Fahr macht nicht den<br />

String erfahren<br />

Sonderzeichen haben spezielle<br />

Bedeutung<br />

• . ˆ$ * + ? { } [ ] \ | ( )<br />

<br />

<br />

fahr<br />

erfahren<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 269 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Auswahlbereiche für ein Zeichen<br />

Auswahl mit []<br />

[abcde]<br />

[a-z]<br />

[a-zA-Z]<br />

[abc$ˆ]<br />

[ˆa-z]<br />

[ab\cd]<br />

Einzelnes Zeichen: Matcht entweder a, b, c, d oder e<br />

Bereich: Matcht jeden (einen) Kleinbuchstaben (ASCII)<br />

Bereich: Matcht Groß- und Kleinbuchstaben<br />

Sonderzeichen nicht aktiv in Bereichen. Matcht a, b, c, $ oder ˆ<br />

ˆam Anfang negiert den Bereich. Matcht alles außer Kleinbuchstaben<br />

\ hebt die besondere Bedeutung auf. Matcht a, b, \, c oder d<br />

Vordefinierte Auswahlbereiche<br />

\d Alle Ziffern, [0-9]<br />

\D Alles außer Ziffern, [ˆ0-9]<br />

\s Whitespace, [ \t\n\r\f\v]<br />

\S Alles außer Whitespace,<br />

[ˆ \t\n\r\f\v]<br />

\w Alphanumerische Zeichen,<br />

[a-zA-Z0-9]<br />

\W Alles außer alphanumerischen Zeichen,<br />

[ˆa-zA-Z0-9]<br />

Auch für Nicht-ASCII Zeichensätze<br />

• Beispiel Deutsch: Umlaute<br />

äöüÄÖÜß werden von \w erkannt<br />

• Achtung: locale-Einstellungen<br />

werden berücksichtigt<br />

• Unicode? wieder alles anders...<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 270 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Wiederholungen und Gruppierungen<br />

matcht , , ...<br />

Pa*gei Pgei, Pagei, Paagei, ...<br />

Pa+gei Pagei, Paagei, ...<br />

Pa?gei<br />

Pgei, Pagei und sonst nichts<br />

P[ae]*gei,<br />

Pgei, Pagei, Pegei, Paagei, Paegei, Peagei<br />

wie P(a|e)*gei Peegei, Paaagei, ...<br />

(Pap|Mam)agei<br />

Papagei, Mamagei und sonst nichts<br />

(Pa)+gei Pagei, PaPagei, PaPaPagei, . . .<br />

Pa(pa)+gei Papagei, Papapagei, . . .<br />

Pa(pa){1,3}gei<br />

Papagei, Papapagei, Papapapagei und sonst nichts<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 271 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Besondere Zeichen und Bedeutung<br />

. beliebiges Zeichen {m,n} Wiederholung, mindestens<br />

m mal und maximal n mal<br />

* Wiederholung 0, 1 oder<br />

{n} Exakt n mal<br />

mehrfach<br />

? Wiederholung 0 oder 1 mal [ Beginn Auswahl aus Zeichen<br />

+ Wiederholung 1 oder mehrfach ] Ende Auswahl aus Zeichen<br />

( Beginn einer Gruppierung ˆ Anfang String/Zeile<br />

) Ende einer Gruppierung [ˆ Negation/Auswahl<br />

{ Beginn explizit gezählte<br />

$ Ende String/Zeile<br />

Wiederholung<br />

} Ende explizit gezählte<br />

Wiederholung<br />

| Oder-Auswahl von<br />

Gruppierungen<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 272 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Gierige Ausführung<br />

Von links nach rechts<br />

• Der erste passende Teilausdruck wird<br />

gematcht<br />

• Später passende Teilausdrücke<br />

werden ignoriert<br />

a[bc]+<br />

xabdyaabc<br />

matcht ab,<br />

nicht abc<br />

So viel wie möglich<br />

• Bei dem ersten passenden<br />

Teilausdruck<br />

• So viel wie möglich Zeichen in den<br />

Match bringen<br />

a[bc]+<br />

xadyaabbbcccd<br />

matcht abbbccc,<br />

nicht Teil davon<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 273 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Beispiele<br />

Binärzahlen (0|1[01]*) ohne führende Nullen<br />

Ganze Zahlen 0|([1-9][0-9]*) ohne führende Nullen<br />

Pi 3\.14<br />

Emailadresse \w+([.-]\w+)*@[a-z]\w+(\.[a-z]\w+)+<br />

Einfaches Ausprobieren in der Shell (bash)<br />

• echo | egrep "" # matcht Teilstring<br />

• echo | egrep "ˆ()$" # exakter Match<br />

Beispiel<br />

• $ echo "11110" | egrep "ˆ(0|(1[01]*))$"<br />

11110<br />

$<br />

• $ echo "011110" | egrep "ˆ(0|(1[01]*))$"<br />

$<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 274 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Reguläre Ausdrücke und Wildcards<br />

Reguläre Ausdrücke<br />

Wildcards<br />

Matchen von Strings<br />

In Perl, Python, egrep, . . .<br />

(Meist) erweiterte reguläre Ausdrücke<br />

Beispiel Unterschiede<br />

a* passt auf beliebig viele a’s; * steht<br />

für die Wiederholung des vorherigen<br />

Zeichens<br />

Matchen von Strings<br />

In Shell, DOS, grep<br />

Standard Wildcards<br />

Beispiel Unterschiede<br />

a* passt auf jeden String der mit a<br />

beginnt; * steht für beliebige<br />

Zeichenfolge<br />

a? passt auf leeres Wort oder a a? passt auf jeden zwei Zeichen<br />

langen String, der mit a beginnt<br />

. . .<br />

Weitere Probleme<br />

• Groß-/Kleinschreibung unterschieden?<br />

• Das $-Zeichen als Beginn einer Variable<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 275 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Literatur und Online-Quellen für Reguläre Ausdrücke<br />

Reguläre Ausdrücke allgemein<br />

• http://<br />

regexp-evaluator.de<br />

/tutorial/<br />

• Die Referenz:<br />

Jeffrey E.F. Friedel<br />

Reguläre Ausdrücke<br />

O’Reilly<br />

Reguläre Ausdrücke in Python<br />

• http://docs.python.org/2.7/library/re.html<br />

• http://docs.python.org/dev/howto/regex.html<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 276 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

re-Modul – Reguläre Ausdrücke in Python<br />

Reguläre Ausdrücke in Python<br />

• re-Modul<br />

• Matche, modifiziere, zerteile, ersetze,<br />

. . .<br />

• Kompilation des “Patterns”<br />

• Ausführen auf C-Engine<br />

Ausführlich dokumentiert – Lesen!<br />

Einfaches Beispiel<br />

• Pattern kompilieren<br />

• Matchen<br />

• Ergebnis ausgeben<br />

• oder alles auf einmal<br />

1 >>> import re<br />

2 >>> pattern = re.compile("[a-z]+")<br />

3 >>> match = pattern.match("abc")<br />

4 >>> match.group()<br />

5 ’abc’<br />

6<br />

7 >>> re.match(r’[a-z]+’, "abc").group()<br />

8 ’abc’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 277 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Beispiel – Kompilieren und Matchen<br />

Kompilieren<br />

• Modul-Funktion compile<br />

• Kompilieren eines regulären<br />

Ausdrucks erzeugt Patternobjekt<br />

Matchen<br />

• Methoden des Patternobjekts<br />

• Mit match Suche in einem String ab<br />

Anfang<br />

• Mit search Suche in einem String<br />

irgendwo<br />

• Ergebnis ist Matchobjekt wenn<br />

erfolgreich, sonst None<br />

• Aus Match-Objekt mit group den<br />

Match (String) extrahieren<br />

1 >>> import re<br />

2 >>> pattern = re.compile(r’[a-z]+’)<br />

1 >>> match = pattern.match(’abcABC’)<br />

2 >>> match.group()<br />

3 ’abc’<br />

4 >>> match = pattern.match(’ABCabcABC’)<br />

5 >>> match<br />

6 >>> print match<br />

7 None<br />

8 >>> match.group()<br />

9 AttributeError: ’NoneType’ object has no<br />

10 >>> match = pattern.search(’ABCabcABC’)<br />

11 >>> match.group()<br />

12 ’abc’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 278 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Beispiel – Optionen und Kompakt<br />

Optionen<br />

• re.IGNORECASE ignorieren von<br />

Groß-/Kleinschreibung<br />

• Weitere Optionen: re.LOCALE,<br />

re.MULTILINE, re.DOTALL,<br />

re.UNICODE, . . .<br />

• Optionen mit Oder | verknüpft<br />

Kompakter Code<br />

• re-Modul stellt Funktionen zur<br />

Verfügung<br />

1 >>> pattern = re.compile(r’[a-z]+’,<br />

2 re.IGNORECASE)<br />

3 >>> match = pattern.search(’ABCabcABC’)<br />

4 >>> match.group()<br />

5 ’ABCabcABC’<br />

1 >>> re.search(’[a-z]+’,<br />

2 "ABCabcABC")<br />

3 <br />

4 >>> re.search(’[a-z]+’,<br />

5 "ABCabcABC").group()<br />

6 ’abc’<br />

7<br />

• Alles in einem Ausdruck möglich >>> re.search(’[a-z]+’,<br />

8 "ABCabcABC",<br />

9 re.IGNORECASE).group()<br />

10 ’ABCabcABC’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 279 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Backslash-Zirkus<br />

Problem<br />

• Mit \ (Backslash) werden Sonderzeichen Ihres besonderen Status beraubt<br />

• Viele Backslashes in Python sind ein Problem<br />

Lösung<br />

• Text \section matchen benötigt \\\\section als Pattern<br />

• Ein \ um das Backslash im Python String zu haben<br />

• Die beiden anderen um das zweite Backslash für den regulären Ausdruck zu haben<br />

• Benutze “raw” Strings in dem alle Zeichen ohne Sonderstatus vorkommen<br />

• r"\\section" entspricht "\\\\section"<br />

1 >>> re.search(’\\\\section’, "dies ist \\section wichtig").group()<br />

2 ’\\section’<br />

3 >>> print re.search(’\\\\section’, "dies ist \\section wichtig").group()<br />

4 \section<br />

5 >>> re.search(r’\\section’, "dies ist \\section wichtig").group()<br />

6 ’\\section’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 280 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Gruppierungen<br />

Gruppierungen<br />

• Teilbereich im Pattern, die<br />

referenziert werden können<br />

• Klammern im Pattern<br />

Zugriff auf Gruppierungen<br />

• groups(): Alle Gruppierungen<br />

• groups(i): Die i.-te Gruppe,<br />

definiert durch i öffnende<br />

Klammern im Pattern<br />

• group(0), group(): Der gesamte<br />

Match<br />

Zurückreferenzieren durch \i im Pattern<br />

• Beispiel: Suche doppeltes<br />

Vorkommen<br />

1 >>> pat = r’(a(b)c)d’<br />

2 >>> s = "abcd"<br />

3 >>> re.search(pat, s).groups()<br />

4 (’abc’, ’b’)<br />

5 >>> re.search(pat, s).group()<br />

6 ’abcd’<br />

7 >>> re.search(pat, s).group(0)<br />

8 ’abcd’<br />

9 >>> re.search(pat, s).group(1)<br />

10 ’abc’<br />

11 >>> re.search(pat, s).group(2)<br />

12 ’b’<br />

13 >>> re.search(pat, s).group(3)<br />

14 IndexError: no such group<br />

15 >>> re.search(pat, s).group(0, 1, 2)<br />

16 (’abcd’, ’abc’, ’b’)<br />

17 >>> s = "Ist doppelt doppelt drin"<br />

18 >>> pat = r’([a-z]+ )\1’<br />

19 >>> print re.search(pat, s).group()<br />

20 doppelt doppelt<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 281 / 326


<strong>Programmieren</strong> in Python<br />

Reguläre Ausdrücke<br />

Modifizieren von Strings<br />

Zerteilen von Strings<br />

• re.split(, )<br />

• Gibt Liste von Strings zurück<br />

• Zerteilt bei jedem<br />

Match von <br />

Suchen und Ersetzen<br />

• re.sub(,,)<br />

• Gibt neuen String zurück<br />

• Bei jedem Match von <br />

in wird <br />

stattdessen eingesetzt<br />

1 >>> pat = r’\W+’<br />

2 >>> s = "Das ist ein netter kleiner Test"<br />

3 >>> re.split(pat, s)<br />

4 [’Das’,’ist’,’ein’,’netter’,’kleiner’,’Test’]<br />

1 >>> pat = ’(blaue|weisse|rote)’<br />

2 >>> neu = "bunte"<br />

3 >>> s = "Die blaue Socke und der rote Ball"<br />

4 >>> re.sub(pat, neu, s)<br />

5 ’Die bunte Socke und der bunte Ball’<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 282 / 326


Thread-Programmierung<br />

Einführung<br />

Multitasking<br />

Multitasking<br />

• Mehrere Dinge “gleichzeitig” tun<br />

• Erwartetes Verhalten auf Rechnern<br />

• Musik, Web (+ Animation), Download<br />

• Ein “Ding” ist meist ein Prozess<br />

• Eigener Speicher<br />

• Eigener Ausführungsstrang/-faden<br />

• Beispiel: P1, P2 und P3/4 parallel; P4 nach nach P3<br />

Prozessoren/Kerne und Prozesse<br />

• Ausführung der Prozesse auf Prozessoren/Kernen<br />

• Multitasking auch bei einem Kern<br />

• Zeitscheiben unterteilen Prozessorzeit<br />

• Jeder Prozess erhält abwechselnd eine (sehr sehr<br />

kleine) Zeitscheibe<br />

• Bei vielen Kernen mehr (parallele Zeitscheiben)<br />

• Aus Benutzersicht alles quasi gleichzeitig<br />

Zeit<br />

Zeit<br />

P3<br />

P1 P2<br />

P4<br />

P3<br />

P1 P2<br />

P4<br />

Zeitscheibe<br />

Prozessor<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 283 / 326


Thread-Programmierung<br />

Einführung<br />

Threads<br />

Prozesse<br />

• Eigener Speicher, eigener Ausführungsfaden<br />

P1<br />

P2<br />

• Fehler in einem Prozess betrifft nur diesen Prozess<br />

• Bei C mit Speicherfehler (Segmentation fault) lief alles<br />

außer Ihrem Prozess weiter<br />

• Schwergewichtige Umschaltung der Zeitscheiben,<br />

viel Aufwand je Kontextwechsel<br />

Zeit<br />

Threads<br />

• Teilen sich Speicher, eigener Ausführungsfaden<br />

P1<br />

P2<br />

• Threads innerhalb eines Prozesses<br />

• Leichtgewichtiges Umschalten der Zeitscheiben,<br />

weniger Aufwand je Kontextwechsel<br />

T1 T2 T3<br />

T4<br />

T5<br />

T6<br />

T7<br />

• Verteilung Zeitscheiben auf alle Threads aller<br />

Prozesse (bei Betriebssystemunterstützung)<br />

Zeit<br />

• Nebenläufigkeit als Programmiermodell<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 284 / 326


Thread-Programmierung<br />

Einführung<br />

Thread-Programmierung<br />

<strong>Programmieren</strong> mit Nebenläufigkeit<br />

• Mehrere Ausführungsstränge/-fäden quasi gleichzeitig bei<br />

gemeinsamen Daten/Ressourcen<br />

• Tausende von Threads möglich, leichtgewichtiger<br />

• Komplex und mächtig bei Verwendung<br />

Weit verbreitet in Programmierumgebungen<br />

• In C/C++ mit Bibliotheken, nutzen Betriebssystemunterstützung<br />

• In Java Teil der Sprache/JVM mit Bibliotheken<br />

• In Python ähnliche API wie in Java<br />

Einsatzgebiete<br />

• Kein Warten bei I/O-Operationen, Überbrücken Latenzen bei<br />

Netzwerkkommunikation; zum Beispiel bei UI kein “Einfrieren der UI” mehr<br />

• Nutzung von Mehrkernarchitekturen, parallele Algorithmen, Verteilen der<br />

Arbeitslast auf mehrere Kerne<br />

• Leider nicht mit CPython (oder PyPy) aber mit Jython<br />

• In CPython ist Alternative multiprocessing-Modul<br />

Globale Daten<br />

T1 T2 T3<br />

T4<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 285 / 326


Thread-Programmierung<br />

Thread-Programmierung in Python<br />

Thread-Programmierung in Python<br />

Java-Style<br />

• Thread-API modelliert nach Java<br />

• threading-Modul, Thread-Klasse<br />

• Methode run überschreiben<br />

Beispiel – die i.-te Primzahl<br />

• Primzahlgenerator prim gegeben<br />

• Klasse erbt von threading.Thread<br />

• Bei Initialisierung i merken<br />

• Methode run, solange Primzahlen bis<br />

i.-te erreicht, Ausgabe<br />

• Instanzvariablen und lokale Variablen<br />

für den Thread<br />

• p und e sind thread-lokale Variablen<br />

(auf dem Stack)<br />

1 import threading, sys<br />

2 from primegen import primes<br />

3<br />

4 class IthPrime(threading.Thread):<br />

5 def __init__(self, i):<br />

6 threading.Thread.__init__(self)<br />

7 self.i = i<br />

8 def run(self):<br />

9 p = primes()<br />

10 for _ in range(self.i):<br />

11 e = p.next()<br />

12 self.ith_prime = e<br />

13 print "done %d, %d" % (self.i, e)<br />

14 def get_ith_prim():<br />

15 return self.ith_prime<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 286 / 326


Thread-Programmierung<br />

Thread-Programmierung in Python<br />

Wiederholung – Primzahlgenerator<br />

Generieren von Primzahlen<br />

• 2 und 3 sind Primzahlen<br />

• Ab da in Zweier-Schritten, wenn<br />

teilerfrei<br />

primegen.py<br />

1 def _teiler(x):<br />

2 return [t for t in range(2, x)<br />

3 if x%t == 0]<br />

4<br />

5 def primes():<br />

6 yield 2<br />

7 yield 3<br />

8 i = 5<br />

9 while True:<br />

10 if _teiler(i) == []:<br />

11 yield i<br />

12 i += 2<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 287 / 326


Thread-Programmierung<br />

Thread-Programmierung in Python<br />

Thread starten und auf Ende warten<br />

Thread starten<br />

• Instanz erzeugen und Methode start<br />

• Asynchron, kehrt sofort zurück<br />

• Seiteneffekt ist, dass Thread los läuft<br />

•<br />

6<br />

Thread beendet sobald run beendet ist t = IthPrime(i)<br />

7 t.start()<br />

Auf Ende warten<br />

8 print "compute in background"<br />

• Eventuell würde Haupt-Thread sich 9 t.join()<br />

beenden (ohne weitere Maßnahme) 10 s = "Die %d.te Primzahl ist %d"<br />

11 print s % (i, t.ith_prime)<br />

• Methode join auf Thread-Instanz<br />

12 print "ready"<br />

blockiert und wartet auf das Ende des<br />

Threads<br />

Zugriff auf Daten<br />

• Zuweisungen Python: atomar, sichtbar<br />

(nicht wie in Java)<br />

• Direkter Zugriff auf Attribute in<br />

Ordnung<br />

1<br />

2 if __name__ == ’__main__’:<br />

3 i = 3<br />

4 if sys.argv[1:]:<br />

5 i = int(sys.argv[1])<br />

$ python ith_prime.py 1000<br />

compute in background<br />

done 1000, 7919<br />

Die 1000.te Primzahl ist 7919<br />

ready<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 288 / 326


Thread-Programmierung<br />

Thread-Programmierung in Python<br />

Mehrere Threads<br />

Mehrere Threads<br />

• Beispiel 3 Threads für 1000.te,<br />

1001.te und 1002.te Primzahl<br />

• Jeweils auf Threads warten<br />

• Ausgabe der Strings (in richtiger<br />

Reihenfolge)<br />

Reihenfolge in den Threads<br />

• Nicht vorhersagbar<br />

• Reihenfolge der done Ausgabe<br />

variiert<br />

1 if __name__ == ’__main__’:<br />

2 i = int(sys.argv[1])<br />

3 ts = [IthPrime(j)<br />

4 for j in range(i, i+3)]<br />

5 for t in ts:<br />

6 t.start()<br />

7 for t in ts:<br />

8 t.join()<br />

9 for t in ts:<br />

10 s = "Die %d.te Primzahl ist %d"<br />

11 print s % (t.i, t.ith_prime)<br />

$ python ith_prime_mehrere.py 1000<br />

done 1000, 7919<br />

done 1002, 7933<br />

done 1001, 7927<br />

Die 1000.te Primzahl ist 7919<br />

Die 1001.te Primzahl ist 7927<br />

Die 1002.te Primzahl ist 7933<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 289 / 326


Thread-Programmierung<br />

Kontrolle Ablauf<br />

Threads – Kontrolle Ablauf<br />

Unmöglich Thread von außen zu stoppen<br />

• Es kann keine Möglichkeit geben, die<br />

immer funktioniert<br />

• Anwendungsentwickler muss entsprechende<br />

Möglichkeiten vorsehen<br />

Ansatz<br />

• Methoden zum Setzen von Variablen<br />

• Periodische Überprüfung der<br />

Variablen<br />

• Synchronisation ok (in Python)<br />

• Ein Thread liest, anderer schreibt<br />

• Bool immer komplett geändert<br />

• Aktuelle Werte in CPython immer<br />

gleich sichtbar (nicht in Java)<br />

1 from threading import Thread<br />

2 from time import sleep<br />

3<br />

4 class Incer(Thread):<br />

5 def __init__(self):<br />

6 Thread.__init__(self)<br />

7 self.weiter = True<br />

8 def run(self):<br />

9 x = 0<br />

10 while self.weiter:<br />

11 x += 1<br />

12 sleep(1) # 1 Sekunde schlafen<br />

13 print "x", x<br />

14 def anhalten(self):<br />

15 self.weiter = False<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 290 / 326


Thread-Programmierung<br />

Kontrolle Ablauf<br />

Threads– Kontrolle Ablauf, Verwendung<br />

Beispiel Ausgabe<br />

• isAlive, läuft Thread?<br />

• join verwenden<br />

1 from incer import Incer<br />

2 from time import sleep<br />

3<br />

4 inc = Incer()<br />

5 inc.start()<br />

6 sleep(3)<br />

7 inc.anhalten()<br />

8 print "Lebt?", inc.isAlive()<br />

9 inc.join()<br />

10 print "Lebt?", inc.isAlive()<br />

x 1<br />

x 2<br />

Lebt? True<br />

x 3<br />

Lebt? False<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 291 / 326


Thread-Programmierung<br />

Kontrolle Ablauf<br />

Threads – Ende erreicht?<br />

Niemals aktiv warten!<br />

• CPU-Zeit mit Nichtstun/Warten<br />

verschwendet, hohe Last<br />

• Nie, nie, nie tun<br />

Thread.join ist ok<br />

• Wartet, dass Thread beendet wird<br />

• Aktuell laufender Thread hält,<br />

verschwendet aber keine<br />

Prozessorzeit<br />

Nachteil von Thread.join<br />

• Aktueller Thread läuft nicht weiter<br />

(aber das ist Intention)<br />

• Falls # was sinnvolles lange dauert,<br />

dann wird nicht gleich reagiert sobald<br />

der Thread zu Ende ist<br />

1 from incer import Incer<br />

2 from time import sleep<br />

3<br />

4 inc = Incer()<br />

5 # Thread beginnt zu laufen<br />

6 inc.start()<br />

7 while inc.isAlive(): # busy wait, boese<br />

8 pass<br />

9 # weiter nach Thread-Ende<br />

1 from incer import Incer<br />

2 from time import sleep<br />

3<br />

4 inc = Incer()<br />

5 inc.start()<br />

6 # was sinnvolles<br />

7 inc.join()<br />

8 # Ergebnis des Threads verwenden<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 292 / 326


Thread-Programmierung<br />

Kontrolle Ablauf<br />

Aktion nach Ende Thread – Naja<br />

Ziel<br />

• Etwas nach Ende eines Threads tun<br />

• Direkt, wenn die Berechnung im<br />

Thread zu Ende ist<br />

Fragwürdige Umsetzung<br />

• Verarbeitung im Haupt-Thread<br />

• Warten bis Berechnungs-Thread am<br />

Ende<br />

Problem<br />

• Falls # was sinnvolles lange dauert<br />

• Keine sofortige Reaktion falls<br />

Berechnung zu Ende<br />

1000.te Primzahl ist 7919<br />

1 import threading, primegen<br />

2 class Langlaeufer(threading.Thread):<br />

3 def __init__(self, iteprim):<br />

4 threading.Thread.__init__(self)<br />

5 self.iteprim = iteprim<br />

6 def run(self):<br />

7 p = primegen.primes()<br />

8 for _ in range(self.iteprim):<br />

9 e = p.next()<br />

10 self.prim = e<br />

11 def get_prim(self):<br />

12 return self.prim<br />

13 if __name__ == ’__main__’:<br />

14 ite = 1000<br />

15 t = Langlaeufer(ite)<br />

16 t.start()<br />

17 # was anderes sinnvolles<br />

18 t.join()<br />

19 tup = (ite, t.get_prim())<br />

20 print "%d.te Primzahl ist %d" % tup<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 293 / 326


Thread-Programmierung<br />

Kontrolle Ablauf<br />

Aktion nach Ende Thread – Besser<br />

Bessere Umsetzung<br />

• Verarbeitung noch im<br />

Berechnungs-Thread<br />

• Callback-Funktion mit übergeben<br />

Vorteile<br />

• Es wird sofort bei Ende der<br />

Berechnung mit dem<br />

Berechnungsergebnis weiter<br />

gearbeitet<br />

• Main-Thread wird nicht beansprucht<br />

• Durch Übergabe “Callback” bleibt<br />

Implementierung unabhängig<br />

1000.te Primzahl ist 7919<br />

1 import threading, primegen<br />

2 class Langlaeufer(threading.Thread):<br />

3 def __init__(self, itep, ende=None):<br />

4 threading.Thread.__init__(self)<br />

5 self.iteprim = itep<br />

6 self.am_ende = ende<br />

7 def run(self):<br />

8 p = primegen.primes()<br />

9 for _ in range(self.iteprim):<br />

10 e = p.next()<br />

11 self.prim = e<br />

12 self.am_ende(self.prim)<br />

13 if __name__ == ’__main__’:<br />

14 ite = 1000<br />

15 def print_prim(iteprim):<br />

16 tup = (ite, iteprim)<br />

17 print "%d.te Primzahl ist %d" % tup<br />

18 t = Langlaeufer(ite, print_prim)<br />

19 t.start()<br />

20 # was anderes sinnvolles<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 294 / 326


Thread-Programmierung<br />

Kritischer Wettlauf, Race Condition<br />

Reihenfolgeproblem<br />

Thread-Ausführung ist nicht-deterministisch<br />

• Keine Aussage welcher Thread zuerst beendet wird möglich<br />

• Keine Aussage welcher Thread(Teil) vor/nach anderem Thread(Teil) ausgeführt<br />

• Keine Aussage wann welche Anweisung in einem Thread unterbrochen wird<br />

Problem bei gemeinsam geschriebenen (shared) Daten<br />

• Bei getrennt genutzten oder Nur-Lese-Daten kein Problem<br />

• Wann immer möglich Thread-lokale Daten verwenden, idealerweise keine shared<br />

Daten oder nur lesbare Daten<br />

• Falls shared Daten nur lesbar sind und bei gemeinsamer Verwaltung sicher initialisiert<br />

sind, keine Inkonsistenz möglich<br />

• Reihenfolge des Schreibens bei gemeinsamen Daten potenziell problematisch<br />

• Zusätzliche Ablauf-Fehler bei ansonsten “sequenziell korrektem” Programm möglich<br />

• Kritischer Wettlauf (race condition)<br />

Lösungsansatz<br />

• Kritische Sektionen identifizieren und synchronisieren<br />

• Nur ein Ausführungsstrang in kritischer Sektion (Sperren)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 295 / 326


Thread-Programmierung<br />

Kritischer Wettlauf, Race Condition<br />

Kritischer Wettlauf – Beispiel Incer<br />

Globale Variable x<br />

• Initial 0<br />

• Durch zwei Threads um 1 erhöht<br />

Problem<br />

• x+=1 sind drei unterbrechbare<br />

Anweisungen<br />

• Lese (read/r) x in y<br />

• Berechne y = y + 1<br />

• Schreibe (write/w) y in x<br />

• Lesen und Schreiben der gleichen<br />

Variable x, Race condition<br />

• y unkritisch, thread-lokal, zwei Mal y<br />

y<br />

6<br />

7<br />

Thread-1<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

y=r(x)<br />

y+=1<br />

x<br />

0<br />

? 12 ?<br />

x<br />

6<br />

Thread-2<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

x+=1<br />

y=r(x)<br />

y+=1<br />

y<br />

6<br />

7<br />

Kritischer Wettlauf<br />

7<br />

x=w(y)<br />

y=w(y)<br />

7<br />

• Quasi gleichzeitiges Ausführen in<br />

kritischem Bereich<br />

Kritischer<br />

Bereich<br />

7<br />

statt 8<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 296 / 326


Thread-Programmierung<br />

Kritischer Wettlauf, Race Condition<br />

Unsynchronisierter Incer in Python<br />

Incer<br />

• x ist globale Variable auf Modulebene,<br />

die mehrmals erhöht wird<br />

• Instanzvariable runs (thread-lokal), wie<br />

häufig wird x je Thread erhöht<br />

• In run jedes Threads das<br />

Inkrementieren jeweils runs mal<br />

Ausführen<br />

• Zwei Threads<br />

• 1 Million Mal erhöhen je Thread<br />

• Laufen lassen, Überraschung<br />

• Unvorhersagbares Verhalten<br />

• x meist < 2 Millionen<br />

• Falsch, Nebenläufigkeits-Bug<br />

Oooops 1488923 statt 2000000<br />

1 from threading import Thread<br />

2 x=0<br />

3 class Incer(Thread):<br />

4 def __init__(self, runs):<br />

5 Thread.__init__(self)<br />

6 self.runs = runs<br />

7 def run(self):<br />

8 global x<br />

9 for _ in xrange(self.runs):<br />

10 x += 1<br />

11 if __name__ == ’__main__’:<br />

12 runs = 10**6<br />

13 inc1, inc2 = Incer(runs), Incer(runs)<br />

14 inc1.start()<br />

15 inc2.start()<br />

16 inc1.join()<br />

17 inc2.join()<br />

18 if x != 2*runs:<br />

19 print "Oooops",x,"statt",2*runs<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 297 / 326


Thread-Programmierung<br />

Kritischer Wettlauf, Race Condition<br />

Kritischer Bereich<br />

Kritischer Wettlauf<br />

• Potenzieller Fehler durch quasi-gleichzeitiges<br />

Ausführen von kritischen Bereichen<br />

Kritischer Bereich<br />

• Anweisungsfolge, mit zusammenhängendem Lesen<br />

und Schreiben auf geteilten Daten<br />

• Zusammengesetzte Aktionen wie zum Beispiel<br />

“check then act”<br />

• Synchronisation um sicherzustellen, dass immer nur<br />

ein Thread sich in einem kritischen Bereich befindet<br />

Beispiele für kritischen Bereich<br />

• x += 1, Lesen/ Schreiben gemeinsamer Variable<br />

• “check” (Warteschlange nicht leer?) “then act” (hole<br />

erstes Element der Warteschlange), nicht-leere<br />

Warteschlange nicht garantiert (durch anderen<br />

Thread zwischenzeitlich geleert)<br />

1 # Beginn kritischer Bereich<br />

2 x += 1<br />

3 # Ende kritischer Bereich<br />

1 # Beginn kritischer Bereich<br />

2 y = x<br />

3 y += 1<br />

4 x = y<br />

5 # Ende kritischer Bereich<br />

1 # Beginn kritischer Bereich<br />

2 if not queue.empty():<br />

3 v = queue.get_nowait()<br />

4 # Ende kritischer Bereich<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 298 / 326


Thread-Programmierung<br />

Sperren<br />

Synchronisation mit Sperren<br />

Kritischer Bereich: x+=1<br />

Sperr-Objekt<br />

• Bietet sichere Sperre, atomare<br />

Operation zur Sperrverwaltung<br />

• acquire: Belegt Sperre (Anfrage), falls<br />

Sperre schon belegt, wird aktuell<br />

6<br />

7<br />

Thread.__init__(self)<br />

self.runs = runs<br />

8 def run(self):<br />

anfragender Thread suspendiert<br />

9 global x<br />

(schlafen gelegt)<br />

10 for _ in xrange(self.runs):<br />

• release: Gibt belegte Sperre wieder 11 sperre.acquire() # Start sicher<br />

frei (sollte durch diesen Thread belegt 12 x += 1 # kritischer Bereich<br />

worden sein, sonst wird es schwierig<br />

zu durchschauen)<br />

13<br />

14<br />

sperre.release() # Ende sicher<br />

if __name__ == ’__main__’:<br />

15 runs = 10**6<br />

• Best-Practice: acquire/release-Block<br />

16 inc1, inc2 = Incer(runs), Incer(runs)<br />

umschließt kritischen Bereich, 11–13<br />

17 inc1.start(); inc2.start()<br />

gut, da alles gesichert ;-)<br />

1 from threading import Thread, Lock<br />

2 x = 0<br />

3 sperre = Lock() # Guard<br />

4 class Incer(Thread):<br />

5 def __init__(self, runs):<br />

18 inc1.join(); inc2.join()<br />

19 if x == 2*runs:<br />

20 print "gut, da alles gesichert ;-)"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 299 / 326


Thread-Programmierung<br />

Sperren<br />

Sperren ist aufwendig<br />

Sperren ist aufwendig<br />

• Unterstützung des Betriebssystems,<br />

der Hardware (spezielle Instruktionen)<br />

• Kontextwechsel bei Suspendierung<br />

des Threads durch belegte Sperre<br />

5<br />

6<br />

inc1, inc2 = Incer(runs), Incer(runs)<br />

inc1.start(); inc2.start()<br />

7 inc1.join(); inc2.join()<br />

• Beispiel, hohe Wahrscheinlichkeit<br />

8 if __name__ == ’__main__’:<br />

blockierter Bereich (hohe “Contention”)<br />

9 runs = 10**7<br />

• (eine Größenordnung langsamer)<br />

Best-Practice<br />

• Sperren so kurz und gezielt wie<br />

möglich, nur so lange wie nötig<br />

• Zugriff auf eine gemeinsame Variable<br />

immer mit derselben Sperre (dem<br />

Guard/Wächter)<br />

• Sperren kritischer Bereich für<br />

Korrektheit notwendig<br />

1 from incerunsync import Incer as UIncer<br />

2 from incermitlock import Incer as SIncer<br />

3 from timeit import default_timer as now<br />

4 def runit(Incer, runs):<br />

10 start = now()<br />

11 runit(UIncer, runs)<br />

12 t = now()-start<br />

13 print "Unsynced: %6.2f s" % t<br />

14 start = now()<br />

15 runit(SIncer, runs)<br />

16 t = now()-start<br />

17 print "Synced : %6.2f s" % t<br />

Unsynced: 1.67 s<br />

Synced : 14.97 s<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 300 / 326


Thread-Programmierung<br />

Sperren<br />

Sperren Lock und RLock<br />

Lock – Sperrobjekt, exklusiv<br />

• acquire(blocked=True), default<br />

• Sperre belegen wenn verfügbar und True zurück<br />

• Wenn belegt, Thread blockieren (schlafen legen)<br />

• acquire(blocked=False)<br />

• Sperre belegen wenn verfügbar und True zurück<br />

• Wenn Sperre schon belegt, dann False zurück<br />

• Erlaubt auf belegte Sperren zu reagieren<br />

• release()<br />

• Gibt belegtes Sperrobjekt frei<br />

• Ausnahme, falls Sperre nicht belegt<br />

RLock – Sperrobjekt, reentrant, wie Lock plus<br />

• Erlaubt verschachtelte acquire/release Aufrufe<br />

• Sonst acquire();acquire() Deadlock<br />

• Bei RLock wird nur ein Zähler erhöht<br />

• Verwendung: Sichere Methode in sicherer Methode<br />

• Verhalten wie in Java<br />

1 from threading import RLock<br />

2 sperre = RLock()<br />

3 class C(object):<br />

4 def a(self):<br />

5 sperre.acquire()<br />

6 print "methode a"<br />

7 self.b()<br />

8 sperre.release()<br />

9 def b(self):<br />

10 sperre.acquire()<br />

11 print "methode b"<br />

12 sperre.release()<br />

13<br />

14 if __name__ == ’__main__’:<br />

15 c = C()<br />

16 c.a()<br />

methode a<br />

methode b<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 301 / 326


Thread-Programmierung<br />

Sperren<br />

Sichere Objekte, Monitor<br />

Bisher: Konventionen<br />

• Globale Objekte x und sperre<br />

• Konvention, dass jeder, der auf x<br />

zugreift diesen Bereich mit sperre<br />

sperren muss<br />

• Fehleranfällig (nicht perfekter<br />

Entwickler)<br />

Besser: Kapselung in sicherem Objekt<br />

• Eigene Klasse mit sicheren<br />

Zugriffsmethoden<br />

• synchronized in Java<br />

• Lokales Sperrobjekt in Instanz der<br />

Klasse<br />

• In Java meist Instanzobjekt selbst<br />

• Typisches Pattern bei Methode value,<br />

sonst release schwierig<br />

counter.py<br />

1 from threading import RLock<br />

2 class Counter(object):<br />

3 def __init__(self):<br />

4 self.count = 0<br />

5 self._lock = RLock()<br />

6 def inc(self):<br />

7 self._lock.acquire()<br />

8 self.count += 1<br />

9 self._lock.release()<br />

10 def value(self):<br />

11 self._lock.acquire()<br />

12 ret = self.count<br />

13 self._lock.release()<br />

14 return ret<br />

Counter ist ein Monitor<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 302 / 326


Thread-Programmierung<br />

Sperren<br />

Sichere Objekte, Monitor, Verwendung<br />

Incer mit Counter<br />

• Counter als sicheres Objekt<br />

• Instanz von Counter zum Zählen<br />

Vorteile<br />

• Verwender (Entwickler) von Counter<br />

muss keine Sperren verwenden<br />

• Entwickler kann keine Sperren<br />

vergessen<br />

RLock teurer in Python,<br />

Beispiel 2,5 Mal langsamer<br />

gut, da alles gesichert ;-)<br />

1 from threading import Thread<br />

2 from counter import Counter<br />

3 class Incer(Thread):<br />

4 def __init__(self, counter, runs):<br />

5 Thread.__init__(self)<br />

6 self.counter = counter<br />

7 self.runs = runs<br />

8 def run(self):<br />

9 for _ in xrange(self.runs):<br />

10 self.counter.inc()<br />

11 if __name__ == ’__main__’:<br />

12 runs = 10**6<br />

13 counter = Counter()<br />

14 inc1 = Incer(counter, runs)<br />

15 inc2 = Incer(counter, runs)<br />

16 inc1.start(); inc2.start()<br />

17 inc1.join(); inc2.join()<br />

18 if 2*runs == counter.value():<br />

19 print "gut, da alles gesichert ;-)"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 303 / 326


Thread-Programmierung<br />

Sperren<br />

Das with-Statement<br />

with-Statement, ein Block<br />

• Default-Operationen bei Eintritt<br />

__enter__ Austritt __exit__ aus Block<br />

• Beispiele: Bei Datei öffnen/schließen,<br />

bei Sperre belegen/freigeben<br />

• Seit Python 2.6<br />

Beispiel: Counter-Objekt aufgeräumter<br />

• Ausführung, hohe Contention<br />

1 from threading import Thread<br />

2 from counterwith import Counter<br />

3 from IncerCounter import Incer<br />

4 no_incers, incruns = 300, 1000<br />

5 counter = Counter()<br />

6 incers = [Incer(counter, incruns) for _ in range(no_incers)]<br />

7 for incer in incers: incer.start()<br />

8 for incer in incers: incer.join() # barrier<br />

1 from threading import RLock<br />

2 class Counter(object):<br />

3 def __init__(self):<br />

4 self.count = 0<br />

5 self._lock = RLock()<br />

6 def inc(self):<br />

7 with self._lock:<br />

8 self.count += 1<br />

9 def value(self):<br />

10 with self._lock:<br />

11 return self.count<br />

got 300000 expected 300000<br />

9 print "got", counter.value(), "expected", no_incers*incruns<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 304 / 326


Thread-Programmierung<br />

Sperren<br />

Zwei sichere Objekte kombiniert nicht unbedingt sicher<br />

Zwei sichere Objekte<br />

• Zwei Counter<br />

• Jeder Counter für sich sicher<br />

• Egal wie viele Threads gleichzeitig<br />

erhöhen, jede Erhöhung wird gezählt<br />

• Neuer kritischer Bereich wenn beide<br />

Counter immer gleichzeitig erhöht<br />

werden sollen<br />

Sichern<br />

• Neue Sperre, während Erhöhung<br />

stattfindet<br />

• Alte Sperren jetzt nutzlos, nur noch<br />

Aufwand<br />

47786 Oopps von 100000 Tests: 47%<br />

1 from threading import Thread, RLock<br />

2 from counter import Counter<br />

3 c1, c2 = Counter(), Counter()<br />

4 class ZweiCounter(Thread):<br />

5 def run(self):<br />

6 for _ in range(10**5):<br />

7 c1.inc(); c2.inc()<br />

8 class Peeker(Thread):<br />

9 def run(self):<br />

10 tests, oops = 0, 0<br />

11 for _ in range(10**5):<br />

12 tests += 1<br />

13 if c1.value() != c2.value():<br />

14 oops += 1<br />

15 s = "%d Oopps von %d Tests: %d%%"<br />

16 prozent = oops*100./tests<br />

17 print s % (oops, tests, prozent)<br />

18 zc, p = ZweiCounter(), Peeker()<br />

19 zc.start(); p.start()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 305 / 326


Thread-Programmierung<br />

Gefahren bei der Thread-Programmierung<br />

Gefahren bei der Thread-Programmierung<br />

Safety, Sicherheit<br />

• Vermeide Fehler, die durch Lese/Schreib-Zugriff verschiedener Threads auf<br />

gemeinsame Variable entstehen (Reihenfolge)<br />

• Kein Problem, falls keine gemeinsamen Variablem oder Nur-Lese Variablen<br />

• Ansonsten Einsatz von Sperren<br />

Liveness, Fortschritt<br />

• Irgend etwas sinnvolles wird irgendwann passieren<br />

• Beispiele: Deadlock (wie in DBMS) oder Starvation (Verhungern)<br />

• Schwer zu erkennen und zu beseitigen, sporadisches Auftreten<br />

Performance<br />

• Mehrkosten zur Laufzeit (Ressourcen/Speicher je Thread, Kontextwechsel,<br />

Synchronisation)<br />

• Wenige Threads (bei Berechnung nicht deutlich mehr als Kerne)<br />

• Wenige und kurze Sperren<br />

• Anpassen Algorithmen an verteilte Umgebung<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 306 / 326


Thread-Programmierung<br />

Gefahren bei der Thread-Programmierung<br />

Deadlock<br />

Deadlock, Verklemmung<br />

• Threads warten auf Freigabe von<br />

Ressourcen, die nicht erfolgt<br />

• Kein Fortschritt mehr, unendliches<br />

Warten<br />

• Verschiedene Szenarios möglich<br />

Zweimal sperren auf einer Sperre<br />

10 with self._lock:<br />

• In einem Thread Sperre erhalten<br />

11 self.mach()<br />

• Nochmal Sperre holen, sperrt auf ewig12 def run(self):<br />

Posix Sperren<br />

• Sperren müssen freigegeben werden,<br />

auch wenn derselbe Thread die<br />

Sperre anfordert<br />

• Java-Verhalten mit RLock, dann läuft<br />

Beispiel durch<br />

1 from threading import Thread, Lock<br />

2 class Deadlock(Thread):<br />

3 def __init__(self):<br />

4 Thread.__init__(self)<br />

5 self._lock = Lock()<br />

6 def mach(self):<br />

7 with self._lock:<br />

8 pass<br />

9 def do(self):<br />

13 self.do()<br />

14 print "fertig"<br />

15 d = Deadlock()<br />

16 d.start()<br />

17 d.join()<br />

18 # haengt, nie fertig<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 307 / 326


Thread-Programmierung<br />

Gefahren bei der Thread-Programmierung<br />

Deadlock – Verschränkte Sperren<br />

Verschränkt Sperren auf zwei Sperren<br />

• Ein Thread macht erst l1, dann l2<br />

• Ein Anderer erst l2, dann l1<br />

• Deadlock, sobald do und mach<br />

verschränkt ausgeführt werden<br />

Lösung<br />

• mach: l1 gesperrt, Threadwechsel<br />

• do: l2 gesperrt, warte auf l1<br />

• mach: warte auf l2<br />

• Sperrordnung, wie bei DBMS<br />

• Zum Beispiel l1 immer vor l2<br />

d1<br />

l1<br />

l2<br />

d2<br />

deadlockverschr.py<br />

1 from threading import Thread, Lock<br />

2 l1, l2 = Lock(), Lock()<br />

3 class Deadlock(Thread):<br />

4 def __init__(self, doDo=True):<br />

5 Thread.__init__(self)<br />

6 self.d = doDo<br />

7 def mach(self):<br />

8 with l1:<br />

9 with l2:<br />

10 print "mach"<br />

11 def do(self):<br />

12 with l2:<br />

13 with l1:<br />

14 print "do"<br />

15 def run(self):<br />

16 f = self.do if self.d else self.mac<br />

17 for _ in range(10**4): f()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 308 / 326


Thread-Programmierung<br />

Gefahren bei der Thread-Programmierung<br />

Deadlock – Verschränkte Sperren, Ausführung<br />

Verwendung<br />

• Zwei Instanzen<br />

• Eine mit Sperrreihenfolge<br />

l1, dann l2<br />

• Eine mit Sperrreihenfolge<br />

l2, dann l1<br />

• Meist kein Ende sondern Deadlock,<br />

verschränktes Sperren<br />

1 from deadlockverschr import Deadlock<br />

2<br />

3 d1 = Deadlock(True) # do<br />

4 d2 = Deadlock(False) # mach<br />

5 d1.start()<br />

6 d2.start()<br />

7 d1.join()<br />

8 d2.join()<br />

9<br />

10 # passiert wahrscheinlich nie<br />

11 print "Ganz Fertig"<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 309 / 326


Thread-Programmierung<br />

Besonderheiten bei Threads in Python<br />

Besonderheiten bei Threads in Python<br />

GIL in CPython-Implementierung (und PyPy)<br />

• Global Interpreter Lock (GIL)<br />

• Nur ein Python-Thread kann zu einem Zeitpunkt auf Python-Strukturen zugreifen<br />

• Nur ein Python-Thread läuft zu jedem Zeitpunkt<br />

• Keine effektive Nutzung von Mehrkernsystemen möglich<br />

• Trotzdem sinnvolle Nutzung von Wartezeiten bei Langläufern<br />

• GIL wird bei Warten auf externe Ereignisse (IO) losgelassen<br />

• Thread-Scheduling von Laufzeitumgebung<br />

• Alle 100 Bytecode-Anweisungen<br />

• sys.getcheckinterval, sys.setcheckinterval<br />

• Alternative ab Python 2.6: multithreading<br />

• Arbeitet mit mehreren Python-Prozessen<br />

• Effektive Nutzung von Mehrkernsystemen möglich<br />

Basiert auf thread-Modul<br />

• Low-Level API, für die meisten Umgebungen verwendbar<br />

• Empfehlung: threading verwenden, Wissen für Java-Programmierung verwendbar<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 310 / 326


Thread-Programmierung<br />

Producer/Consumer Pattern<br />

Producer/Consumer<br />

Situation<br />

• Ein Produzent erzeugt Werte<br />

• Ein Konsument verwendet Werte<br />

• Beide können unabhängig voneinander laufen<br />

• Problem: Konsument muss warten, bis Produzent<br />

fertig; Produzent muss warten, bis Konsument fertig<br />

Warteschlange<br />

• Entkopplung von Produzent und Konsument<br />

• Produzent legt fertige Werte in Warteschlange<br />

• Konsument holt Werte aus der Warteschlange<br />

• Warteschlange ist gemeinsames Objekt, Zugriffe<br />

müssen synchronisiert werden<br />

• Bei leerer Warteschlange muss Konsument warten<br />

• Bei voller Warteschlange (begrenzte Größe) muss<br />

Produzent warten<br />

• Einfügen/Entfernen nur einer gleichzeitig<br />

Produzent<br />

Konsument<br />

Warteschlange<br />

flexible<br />

Größe<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 311 / 326


Thread-Programmierung<br />

Producer/Consumer Pattern<br />

Producer<br />

Aufgabe<br />

• Erzeuge Zahlen von 1 bis anz<br />

Klasse Producer<br />

• Ein Thread<br />

Gemeinsame Objekte<br />

• Warteschlange, queue<br />

• Sperre auf Warteschlange, qlock<br />

Ausführung, run<br />

• Immer kurz warten<br />

• Zugriff auf Warteschlange als<br />

kritischer Bereich mit Sperren<br />

umschließen<br />

• Jeweils nächstes Element einfügen<br />

producer.py<br />

1 from threading import Thread<br />

2 import time, random<br />

3 class Producer(Thread):<br />

4 def __init__(self, anz, queue, qlock):<br />

5 Thread.__init__(self)<br />

6 self.anz = anz # endlich viele<br />

7 self.queue = queue<br />

8 self.qlock = qlock<br />

9 def run(self):<br />

10 for i in range(1, self.anz+1):<br />

11 # etwas Zeit lassen...<br />

12 time.sleep(random.random()/100.)<br />

13 with self.qlock:<br />

14 self.queue.insert(0, i)<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 312 / 326


Thread-Programmierung<br />

Producer/Consumer Pattern<br />

Consumer<br />

Aufgabe<br />

• Alle Elemente aus<br />

Warteschlange aufsummieren<br />

Klasse Consumer, ein Thread<br />

Gemeinsame Objekte<br />

• Warteschlange, queue<br />

• Sperre auf Warteschl., qlock<br />

Ausführung, run<br />

• Solange noch was kommen<br />

kann oder noch was da ist<br />

• Entferne nächstes Element von<br />

queue und summiere es auf<br />

• Falls kein Element in queue,<br />

ein bisschen warten<br />

consumer.py<br />

1 from threading import Thread<br />

2 import time, random<br />

3 class Consumer(Thread):<br />

4 def __init__(self, queue, qlock):<br />

5 Thread.__init__(self)<br />

6 self.queue, self.qlock = queue, qlock<br />

7 self.summe, self.misses = 0,0<br />

8 self.done = False # soll stoppen<br />

9 def run(self):<br />

10 while not self.done or self.queue:<br />

11 value = None<br />

12 with self.qlock:<br />

13 if self.queue:<br />

14 value = self.queue.pop()<br />

15 if value:<br />

16 self.summe += value<br />

17 else:<br />

18 time.sleep(random.random()/100.)<br />

19 self.misses += 1<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 313 / 326


Thread-Programmierung<br />

Producer/Consumer Pattern<br />

Producer / Consumer<br />

1 from producer import Producer<br />

Gemeinsame Objekte anlegen<br />

2 from consumer import Consumer<br />

• Warteschlange, list<br />

3 from threading import Lock<br />

• Warteschlangensperre, Lock<br />

4<br />

5 anz = 100<br />

Producer/Consumer erzeugen, starten<br />

6 queue = []<br />

• Erste beide erzeugen<br />

7 qlock = Lock()<br />

•<br />

8<br />

Dann beide starten (fast gleichzeitig)<br />

9 producer = Producer(anz, queue, qlock)<br />

Producer/Consumer join<br />

10 consumer = Consumer(queue, qlock)<br />

• Auf Ende des Produzenten warten, nur11<br />

anz viele werden erzeugt<br />

12 producer.start()<br />

13 consumer.start()<br />

• Dem Konsumenten mitteilen, dass<br />

14<br />

keine weiteren Werte kommen werden<br />

15 producer.join()<br />

• Auf Ende Consumer warten<br />

16 consumer.done = True<br />

Ergebnis ist fertig<br />

misses: 91<br />

17 consumer.join()<br />

18<br />

19 print "misses:", consumer.misses<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 314 / 326


Thread-Programmierung<br />

Producer/Consumer Pattern<br />

Performance Problem<br />

Producer produziert zu schnell<br />

• Sehr viel Speicher wird verschwendet<br />

• Lösung: Begrenzte Warteschlange<br />

Warteschlange voll oder leer<br />

• Warteschlange leer: Konsument findet keinen Wert<br />

• Warteschlange voll: Produzent generiert keinen Wert<br />

• Aber in beiden Fällen wir Schleife durchlaufen<br />

• Rechenzeit wird verbraucht ohne Effekt<br />

(Teil-)Lösung bisher<br />

• Wenn Extremsituation eintritt, dann ein bisschen schlafen<br />

• Ist aber nur raten/flicken<br />

Lösungsansatz<br />

• Thread schlafen legen und wieder aufwecken<br />

• Wenn Warteschlange leer, dann soll Konsument schlafen<br />

• Wenn Element eingefügt wird, dann soll Konsument geweckt werden<br />

• Spezielle Konstrukte für Schlafen/Aufwecken sind wait/notify<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 315 / 326


Thread-Programmierung<br />

wait/notify<br />

wait/notify<br />

Condition<br />

• Klasse von threading<br />

• Hält intern Sperre, kann sie auch<br />

beim Initialisieren bekommen<br />

• Implementiert Lock-Interface,<br />

acquire, release<br />

c.acquire()<br />

erzeuge()<br />

c.notify()<br />

c.release()<br />

c = Condition()<br />

c.acquire()<br />

while nixda():<br />

wait()<br />

verwende()<br />

c.release()<br />

• Weitere Methoden wait, notify, notifyAll<br />

wait()<br />

• Lässt Sperre los (Sperre muss belegt sein), legt aktuellen Thread schlafen<br />

• Weiterlaufen erst, wenn notify oder notifyAll auf Condition gerufen wurde<br />

notify()<br />

• Sperre muss belegt sein<br />

• Informiert einen der wartenden Threads, dass es weiter gehen könnte<br />

• Programmierer lässt danach Sperre meist wieder los (release)<br />

notifyAll(): wie notify, nur werden alle Threads informiert<br />

Jedes Java Objekt implementiert wait, notify, notifyAll<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 316 / 326


Thread-Programmierung<br />

wait/notify<br />

Producer mit wait/notify<br />

Aufgabe<br />

• Produzent ohne aktives Warten<br />

Gemeinsame Objekte<br />

• Warteschlange queue als Liste<br />

• Condition cond als Sperre<br />

Producer, Thread<br />

• Von außen abbrechbar mit self.do<br />

• Falls Element in queue, dann keins<br />

mehr produzieren; de facto<br />

Warteschlange mit Länge 1<br />

• Falls ein Element drin ist, dann wird<br />

ein auf cond wartender Thread<br />

geweckt (nach release)<br />

• Es wird langsamer produziert<br />

• Am Ende des Threads werden alle<br />

wartenden Threads geweckt<br />

produceroaw.py<br />

1 from threading import Thread<br />

2 import time, random<br />

3 class Producer(Thread):<br />

4 def __init__(self, queue, cond):<br />

5 Thread.__init__(self)<br />

6 self.do = True<br />

7 self.queue = queue<br />

8 self.cond = cond<br />

9 def run(self):<br />

10 i=0<br />

11 while self.do:<br />

12 with self.cond:<br />

13 if not self.queue:<br />

14 self.queue.append(i)<br />

15 self.cond.notify()<br />

16 i += 1<br />

17 # time.sleep(0.01)<br />

18 with self.cond:<br />

19 self.cond.notifyAll()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 317 / 326


Thread-Programmierung<br />

wait/notify<br />

Consumer mit wait/notify<br />

Aufgabe<br />

• Schlafen legen, falls nichts<br />

verfügbar<br />

Gemeinsame Objekte<br />

• Warteschlange queue als Liste<br />

• Condition cond als Sperre<br />

Consumer, Thread<br />

• Wenn queue leer, dann schlafen<br />

mit wait<br />

• Schlafen immer in<br />

while-Schleife<br />

• Nach Aufwecken in gesperrtem<br />

Zustand<br />

consumeroaw.py<br />

1 from threading import Thread<br />

2 class Consumer(Thread):<br />

3 def __init__(self, queue, cond, id):<br />

4 Thread.__init__(self)<br />

5 self.do, self.id = True, id<br />

6 self.queue, self.cond = queue, cond<br />

7 def run(self):<br />

8 summe = 0<br />

9 while self.do:<br />

10 self.cond.acquire()<br />

11 while not self.queue and self.do:<br />

12 self.cond.wait()<br />

13 value = None<br />

14 if self.queue:<br />

15 value = self.queue.pop()<br />

16 self.cond.release()<br />

17 if value: summe += value<br />

18 msg = "done %d %6d" % (self.id, summe)<br />

19 print msg<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 318 / 326


Thread-Programmierung<br />

wait/notify<br />

Producer/Consumer mit wait/notify<br />

Aufgabe<br />

• Ein Produzent<br />

• Zwei Konsumenten, jeder liest<br />

• Keine Garantie, dass abwechselnd<br />

gelesen wird<br />

• Verhungern (Starvation) möglich<br />

Anmerkungen<br />

• notifyAll bei Producer, damit beide<br />

Konsumenten wach werden am Ende<br />

• Ergebnis bei jedem Durchlauf anders<br />

• Wie viele Zahlen insgesamt addiert<br />

• Wie auf Konsumenten aufgeteilt<br />

• Es ist möglich, dass Zahlen ignoriert<br />

werden beim Generieren<br />

done 1 740240716<br />

done 2 753020403<br />

1 from produceroaw import Producer<br />

2 from consumeroaw import Consumer<br />

3 from threading import Condition<br />

4 import time<br />

5<br />

6 queue = []<br />

7 cond = Condition()<br />

8 producer = Producer(queue, cond)<br />

9 c1 = Consumer(queue, cond, 1)<br />

10 c2 = Consumer(queue, cond, 2)<br />

11 producer.start()<br />

12 c1.start(); c2.start()<br />

13<br />

14 time.sleep(2) # 2 Sek. schlafen<br />

15<br />

16 producer.do = False<br />

17 c1.do, c2.do = False, False<br />

18 c1.join(); c2.join()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 319 / 326


Thread-Programmierung<br />

Spezielle Datentypen für Threading<br />

Spezieller Warteschlangen-Datentyp<br />

Producer/Consumer<br />

• Typisches Pattern bei nebenläufigem <strong>Programmieren</strong><br />

• Zentrale Datenstruktur ist Warteschlange<br />

• Umgeben von Synchronisations- und Warte-Idiomen<br />

Idee – spezielle Queue als vorgefertigter Datentyp<br />

• Sicheres Objekt<br />

• Sperre in Datentyp eingebaut<br />

• Automatisches Sperren bei Einfügen, Holen und Löschen<br />

• Warte-Idiome integriert, automatisch schlafen legen<br />

• Blockierender Zugriff beim Holen, falls noch nichts da<br />

• Blockierender Zugriff beim Einfügen, falls Warteschlange voll<br />

• Optional Pollen zum Zugriff<br />

• Nicht blockierend, Ausnahme, falls voll/leer<br />

• Achtung! Nicht falsch verwenden (Check then act)<br />

Ergebnis: Einfacheres Producer/Consumer Pattern<br />

put_nowait put<br />

Wenn<br />

voll<br />

Queue<br />

Wenn<br />

leer<br />

get_nowait get<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 320 / 326


Thread-Programmierung<br />

Spezielle Datentypen für Threading<br />

Queue<br />

Datenstruktur für Thread-Prog.<br />

• Klasse Queue im Modul Queue<br />

• Warteschlange für konkurrierenden<br />

Zugriff<br />

• Schreiber und Leser<br />

Queue<br />

• put(e)/get()<br />

• Schlüsselwortparameter block=True,<br />

default blockierender Zugriff<br />

• Schlüsselwortparameter<br />

timeout=, default None (ewig),<br />

Maximal Sekunden warten bis<br />

Ausnahme<br />

Wenn möglich dedizierte<br />

Datenstrukturen/Bibliotheken verwenden<br />

consumerqueue.py<br />

1 from threading import Thread<br />

2 from Queue import Empty<br />

3 class Consumer(Thread):<br />

4 def __init__(self, queue, id):<br />

5 Thread.__init__(self)<br />

6 self.do, self.id = True, id<br />

7 self.queue = queue<br />

8 def run(self):<br />

9 summe = 0<br />

10 while self.do:<br />

11 try: # 1 Sek. Timeout<br />

12 val = self.queue.get(True,1)<br />

13 summe += val<br />

14 except Empty:<br />

15 pass<br />

16 msg = "done %d %6d"<br />

17 print msg % (self.id, summe)<br />

• In Java java.util.concurrent<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 321 / 326


Thread-Programmierung<br />

Spezielle Datentypen für Threading<br />

Consumer/Producer mit Queue<br />

producerqueue.py<br />

1 from threading import Thread<br />

2 class Producer(Thread):<br />

3 def __init__(self, queue):<br />

4 Thread.__init__(self)<br />

5 self.do = True<br />

6 self.queue = queue<br />

7 def run(self):<br />

8 i=0<br />

9 while self.do:<br />

0 self.queue.put(i)<br />

1 i += 1<br />

1 from consumerqueue import Consumer<br />

2 from producerqueue import Producer<br />

3 from Queue import Queue<br />

4 import time<br />

5<br />

6 queue = Queue()<br />

7 p = Producer(queue)<br />

8 c1 = Consumer(queue, 1)<br />

9 c2 = Consumer(queue, 2)<br />

10 p.start();<br />

11 c1.start(); c2.start()<br />

12<br />

13 time.sleep(2)<br />

done 2 15994664301<br />

done 1 14952448204<br />

• Es geht nichts verloren<br />

• Effizienter<br />

14<br />

15 p.do = False<br />

16 c1.do, c2.do = False, False<br />

17<br />

18 c1.join(); c2.join()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 322 / 326


Thread-Programmierung<br />

Worker-Thread Pattern<br />

Arbeits-Threads, Worker-Threads<br />

Parallelisierung<br />

• Serialisierung, Hintereinanderausführung, ein Thread<br />

• Parallelisierung: Ein Thread per Aufgabe (Task)<br />

• Problem: Zu extrem, zu viele Threads gleichzeitig, zu<br />

viel Overhead (Kontextwechsel)<br />

Ziel<br />

• Parallelisierung mit wenigen Threads, Worker<br />

• Ein Thread übernimmt mehrere Aufgaben<br />

• Auslastung der wenigen Worker-Threads, Auslastung<br />

des Gesamtsystems, wenig Overhead<br />

Umsetzung<br />

• Warteschlange (Queue) mit Arbeitsaufträgen<br />

• Jeder Thread holt sich (threadsicher) Aufträge und<br />

arbeitet diese ab<br />

• Ohne Arbeit schlafen oder beenden<br />

jetzt<br />

Worker<br />

Thread<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 323 / 326


Thread-Programmierung<br />

Worker-Thread Pattern<br />

Worker Thread zum Addieren / 1<br />

Thread-Verwaltung<br />

• Klassenvariable counter, ein Monitor<br />

zur Thread-ID Verwaltung<br />

• Thread-IDs zwischen 1 und max.<br />

Anzahl Threads<br />

Idee<br />

• Erster Thread (id==1) läuft am<br />

längsten<br />

• Sobald irgendein anderer Thread eine<br />

leere Warteschlange trifft, wird dieser<br />

Thread beendet; es ist ja weniger zu<br />

tun<br />

• Erster Thread läuft aber noch weiter<br />

worker.py<br />

1 from threading import Thread<br />

2 from counterext import Counter<br />

3 from Queue import Empty<br />

4<br />

5 class Worker(Thread):<br />

6<br />

7 count = Counter()<br />

8<br />

9 def __init__(self, queue):<br />

10 Thread.__init__(self)<br />

11 self.queue = queue<br />

12 self.id = Worker.count.inc()<br />

13<br />

14 def run(self):<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 324 / 326


Thread-Programmierung<br />

Worker-Thread Pattern<br />

Worker Thread zum Addieren / 2<br />

Umsetzung – Schleife<br />

• Schleife, beendet Threads mit<br />

hoher ID, nie 1<br />

• Hole erst v1, dann v2<br />

• Holen klappt nicht? Beenden!<br />

• Nur wenn id != 1<br />

• v1 zurück wenn v2 nicht klappt<br />

• Holen klappt? Summiere und<br />

Zahl wieder in Warteschlange<br />

Umsetzung – Beenden<br />

• Zähler wie viele Threads am<br />

Ende erniedrigen<br />

1 while Worker.count.value() >= self.id:<br />

2 v1, v2 = None, None<br />

3 try:<br />

4 v1 = self.queue.get(timeout=.1)<br />

5 except Empty:<br />

6 if self.id > 1: break<br />

7 continue<br />

8 try:<br />

9 v2 = self.queue.get(timeout=.1)<br />

10 except Empty:<br />

11 if (self.id > 1 or<br />

12 self.id==self.count.value()==1):<br />

13 if self.queue.empty():<br />

14 self.queue.put(v1)<br />

15 break<br />

16<br />

• self.queue.put(v1)<br />

Noch ein Element, noch ein<br />

17 continue<br />

Thread (id==1) und keine Arbeit<br />

18 v = v1 + v2<br />

mehr? Ganz fertig, beende auch<br />

19 self.queue.put(v)<br />

letzten Thread<br />

20 Worker.count.dec()<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 325 / 326


Thread-Programmierung<br />

Worker-Thread Pattern<br />

Worker Thread zum Addieren – Verwendung<br />

Verwendung<br />

• Zu addierende Zahlen in queue<br />

• Alle Worker starten, dann warten<br />

• Interessant ist eigentlich nur der mit<br />

id=1, da der sich als Letztes beendet<br />

Kein gutes Beispiel<br />

• Aufwand je Task zu gering (Addition)<br />

• Wohl zu viele Threads für reine<br />

Berechnung (ohne I/O)<br />

• Keine Nutzung von vielen Kernen mit<br />

CPython<br />

Besseres Beispiel nächstes Semester<br />

• Servlet Engine, Thread-Pool<br />

• Web-Request (I/O) im Worker-Thread<br />

1 from worker import Worker<br />

2 from Queue import Queue<br />

3 anzworker, bis = 100, 10**5<br />

4 queue = Queue()<br />

5 for ele in xrange(1, bis+1):<br />

6 queue.put(ele)<br />

7 workers = []<br />

8 for _ in xrange(anzworker):<br />

9 workers.append(Worker(queue))<br />

10 for worker in workers:<br />

11 worker.start()<br />

12 for worker in workers:<br />

13 worker.join()<br />

14 summe = queue.get()<br />

15 print "Summe ist %d" % summe<br />

16 summe = sum(range(1, bis+1))<br />

17 print "Summe sollte sein %d" % summe<br />

Summe ist 5000050000<br />

Summe sollte sein 5000050000<br />

Prof. Dr. Peter Barth (HS-<strong>RheinMain</strong>) <strong>Programmieren</strong> 3 29. Januar 2013 326 / 326

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!