This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
", line 0> Ameisen, eine Einfuehrung
Um Code auf der Stelle zu erzeugen, verwenden Sie die in Beispiel 1-22 gezeigte Klasse. Benutzen Sie die Methode write, um Anweisungen hinzuzufgen und die Methoden indent und dedent, um Struktur hinzuzufgen. Die Klasse erledigt den Rest. Beispiel 1-22: Ein einfaches Werkzeug zur Code-Erzeugung File: builtin-compile-example-3.py import sys, string
15
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-22: Ein einfaches Werkzeug zur Code-Erzeugung (Fortsetzung) class CodeGeneratorBackend: "Einfacher Code-Generator fuer Python" def begin(self, tab="\t"): self.code = [] self.tab = tab self.level = 0 def end(self): self.code.append("") # Zeilenende-Zeichen sicherstellen return compile(string.join(self.code, "\n"), "", "exec") def write(self, string): self.code.append(self.tab * self.level + string) def indent(self): self.level += 1 # in Python 1.5.2 und davor verwende man statt dessen: # self.level = self.level + 1 def dedent(self): if self.level == 0: raise SyntaxError, "interner Fehler im Code-Generator" self.level -= 1 # in Python 1.5.2 und davor verwende man statt dessen: # self.level = self.level - 1 # # Probieren Sie es aus! c = CodeGeneratorBackend() c.begin() c.write("for i in range(5):") c.indent() c.write("print 'Code-Generierung einfach gemacht!'") c.dedent() exec c.end() Code-Generierung Code-Generierung Code-Generierung Code-Generierung Code-Generierung
einfach einfach einfach einfach einfach
gemacht! gemacht! gemacht! gemacht! gemacht!
Python stellt auch eine Funktion namens execfile zur Verfgung, eine Kurzvariante, um Code aus einer Datei zu laden, ihn zu kompilieren und auszufhren. Beispiel 1-23 zeigt, wie man diese Funktion verwenden und emulieren kann.
16
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul _ _builtin_ _ Beispiel 1-23: Verwendung der Funktion execfile File: builtin-execfile-example-1.py execfile("hello.py") def EXECFILE(filename, locals=None, globals=None): exec compile(open(filename).read(), filename, "exec") in locals, globals EXECFILE("hello.py") Nochmals Hallo und willkommen zur Show Nochmals Hallo und willkommen zur Show
Der Inhalt der in Beispiel 1-23 verwendeten Datei hello.py wird in Beispiel 1-24 gezeigt. Beispiel 1-24: Das Skript hello.py File: hello.py print "Nochmals Hallo und willkommen zur Show"
1berladen von Funktionen des Moduls _ _builtin_ _ Da Python erst in den eingebauten Funktionen nachschaut, nachdem es den lokalen und den Modul-Namensraum geprft hat, kann es Situationen geben, in denen Sie das Modul _ _builtin_ _ explizit angeben mssen. Das Skript in Beispiel 1-25 z.B. berschreibt die Funktion open mit einer Version, die eine gewBhnliche Datei Bffnet und prft, ob sie mit einem »magischen« String beginnt. Um die Originalfunktion open verwenden zu kBnnen, wird diese Funktion im Skript explizit mit dem Modulnamen angegeben. Beispiel 1-25: Expliziter Zugriff auf Funktionen des Moduls _ _builtin_ _ File: builtin-open-example-1.py def open(filename, mode="rb"): import __builtin__ file = __builtin__.open(filename, mode) if file.read(5) not in("GIF87", "GIF89"): raise IOError, "keine GIF-Datei" file.seek(0) return file fp = open("samples/sample.gif") print len(fp.read()), "bytes" fp = open("samples/sample.jpg") print len(fp.read()), "bytes" 3565 bytes
17
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-25: Expliziter Zugriff auf Funktionen des Moduls _ _builtin_ _ (Fortsetzung) Traceback (innermost last): File "builtin-open-example-1.py", line 12, in ? File "builtin-open-example-1.py", line 5, in open IOError: keine GIF-Datei
Das Modul exceptions Das Modul exceptions stellt die Hierarchie der Standardausnahmen zur Verfgung. Es wird automatisch importiert, wenn Python gestartet wird, und die Ausnahmen werden zum Modul _ _builtin_ _ hinzugefgt. Sie mssen dieses Modul also normalerweise nicht importieren. Dies ist ein Python-Modul in 1.5.2 und ein eingebautes Modul in 2.0 und sp;ter. Das Modul definiert folgende Standardausnahmen:
· · · · · · · · · 18
Exception wird als Oberklasse fr alle Ausnahmen verwendet. Es wird w;rmstens empfohlen (ist aber noch nicht zwingend erforderlich), daß benutzerdefinierte Ausnahmen ebenfalls von dieser Klasse abgeleitet werden. SystemExit(Exception) wird von der Funktion sys.exit ausgelBst. Wenn diese Ausnahme bis zur obersten Ebene weitergereicht wird, ohne von einer try-exceptKlausel abgefangen zu werden, wird der Interpreter ohne eine Traceback-Meldung beendet. StandardError(Exception) wird als Oberklasse fr alle Standardausnahmen verwendet (außer von SystemExit). KeyboardInterrupt(StandardError) wird ausgelBst, wenn der Benutzer Strg-C (oder irgendein anderes Unterbrechungszeichen) eingibt. Man beachte, daß dies zu seltsamen Fehlern fhren kann, wenn Sie die »alles abfangende« Variante von tryexcept verwenden. ImportError(StandardError) wird ausgelBst, wenn Python ein Modul nicht importieren kann. EnvironmentError wird als Oberklasse fr Ausnahmen verwendet, die von der Umgebung des Interpreters ausgelBst werden kBnnen (d.h., sie werden normalerweise nicht von Fehlern im Programm verursacht). IOError(EnvironmentError) wird verwendet, um I/O-bezogene Fehler zu kennzeichnen. OSError(EnvironmentError) wird verwendet, um Fehler im Modul os zu kennzeichnen. WindowsError(OSError) wird verwendet, um Windows-spezifische Fehler im osModul zu kennzeichnen.
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul exceptions
· · · · · · · · · · · · · · ·
NameError(StandardError) wird ausgelBst, wenn Python einen globalen oder lokalen Namen nicht finden kann. UnboundLocalError(NameError) wird ausgelBst, wenn Ihr Programm versucht, auf eine lokale Variable zuzugreifen, bevor ihr ein Wert zugewiesen worden ist. Diese Ausnahme wird nur in 2.0 und sp;ter verwendet. Frhere Versionen lBsen statt dessen die Ausnahme NameError aus. AttributeError(StandardError) wird ausgelBst, wenn Python ein Instanzattribut, eine Methode, eine Modulfunktion oder irgendeinen anderen qualifizierten Namen nicht finden oder ihm/ihr nichts zuweisen kann. SyntaxError(StandardError) wird ausgelBst, wenn der Compiler auf einen Syntaxfehler stBßt. (2.0 und sp;ter) IndentationError(SyntaxError) wird bei Syntaxfehlern ausgelBst, die durch falsche Einrckung entstanden sind. Diese Ausnahme wird nur in 2.0 und sp;ter verwendet; frhere Versionen lBsen statt dessen einfach die Ausnahme SyntaxError aus. (2.0 und sp;ter) TabError(IndentationError) wird vom Interpreter ausgelBst, wenn die Option -tt verwendet wird, um auf inkonsistente Einrckung zu prfen. Diese Ausnahme wird nur in 2.0 und sp;ter verwendet; frhere Versionen lBsen statt dessen einfach die Ausnahme SyntaxError aus. TypeError(StandardError) wird ausgelBst, wenn eine Operation auf ein Objekt des entsprechenden Typs nicht angewendet werden kann. AssertionError(StandardError) wird ausgelBst, wenn die Anweisung assert fehlschl;gt (d.h. wenn der Ausdruck falsch ist). LookupError(StandardError) wird als Oberklasse fr Ausnahmen verwendet, die ausgelBst werden, wenn ein Sequenz- oder Dictionary-Typ einen bestimmten Index oder Schlssel nicht enth;lt. IndexError(LookupError) wird von Sequenzobjekten ausgelBst, wenn der angegebene Index nicht existiert. KeyError(LookupError) wird von Dictionary-Objekten ausgelBst, wenn der angegebene Schlssel nicht existiert. ArithmeticError(StandardError) wird als Oberklasse fr Ausnahmen verwendet, die mathematische Ursachen haben. OverflowError(ArithmeticError) wird ausgelBst, wenn eine Operation zu einem $berlauf fhrt (z.B. wenn eine ganze Zahl zu groß fr den angegebenen Typ ist). ZeroDivisionError(ArithmeticError) wird ausgelBst, wenn Sie versuchen, eine Zahl durch null zu teilen. FloatingPointError(ArithmeticError) wird ausgelBst, wenn eine Fließkommaoperation fehlschl;gt.
19
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule
· · · · · ·
ValueError(StandardError) wird ausgelBst, wenn ein Argument den richtigen Typ, aber einen ungltigen Wert hat. (2.0 und sp;ter) UnicodeError(ValueError) wird bei Typproblemen mit UnicodeStrings ausgelBst. Dies wird nur in 2.0 und sp;ter verwendet. RuntimeError(StandardError) wird bei verschiedenen Laufzeitproblemen verwendet, inklusive Versuchen, den Rechner im eingeschr;nkten Modus zu verlassen, unerwarteten Hardware-Problemen usw. NotImplementedError(RuntimeError) kann verwendet werden, um Funktionen zu markieren, die noch nicht implementiert sind, oder Methoden, die berschrieben werden sollten. SystemError(StandardError) wird ausgelBst, wenn der Interpreter durcheinanderkommt und das auch mitbekommt. Der Wert der Ausnahme enth;lt eine detailliertere Beschreibung (normalerweise etwas Kryptisches wie eval_code2: NULL globals oder so). Ich kann mich nicht erinnern, in ber fnf Jahren Vollzeitprogrammierung in Python jemals diese Ausnahme gesehen zu haben, aber vielleicht liegt das nur an mir. MemoryError(StandardError) wird ausgelBst, wenn dem Interpreter kein Hauptspeicher mehr zur Verfgung steht. Man beachte, daß dies nur dann passiert, wenn die zugrundeliegenden Routinen zur Speicheralloierung einen Fehler melden. Sie kBnnen oftmals Ihren armen Computer in den Speicherauslagerungswahnsinn treiben, bevor dies passiert.
Sie kBnnen Ihre eigenen Ausnahmeklassen erzeugen. Leiten Sie dazu einfach von der eingebauten Klasse Exception (oder der richtigen Standardausnahme) ab, und berschreiben Sie den Konstruktor und/oder die Methode _ _str_ _, falls nBtig. Beispiel 1-26 zeigt das Modul exceptions. Beispiel 1-26: Verwendung des Moduls exceptions File: exceptions-example-1.py # Python importiert dieses Modul selbstaendig, daher ist # die folgende Zeile nicht unbedingt noetig. # import exceptions class HTTPError(Exception): # zeigt einen Fehler beim HTTP-Protokoll an def __init__(self, url, errcode, errmsg): self.url = url self.errcode = errcode self.errmsg = errmsg def __str__(self): return ( "" % (self.url, self.errcode, self.errmsg) )
20
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os Beispiel 1-26: Verwendung des Moduls exceptions (Fortsetzung) try: raise HTTPError("http://www.python.org/foo", 200, "Not Found") except HTTPError, error: print "url", "=>", error.url print "errcode", "=>", error.errcode print "errmsg", "=>", error.errmsg raise # Ausnahme neu ausloesen url => http://www.python.org/foo errcode => 200 errmsg => Not Found Traceback (innermost last): File "exceptions-example-1", line 16, in ? HTTPError:
Das Modul os Das Modul os stellt eine einheitliche Schnittstelle zu vielen Funktionen des Betriebssystems zur Verfgung. Die meisten Funktionen dieses Moduls werden von plattformspezifischen Modulen wie posix oder nt implementiert. Das Modul os l;dt automatisch die richtige Implementie-
rung, wenn es zum erstenmal importiert wird.
Arbeiten mit Dateien Mit der eingebauten Funktion open kBnnen Sie Dateien erzeugen, Bffnen und bearbeiten, wie in Beispiel 1-27 gezeigt. Dieses Modul enth;lt die zus;tzlichen Funktionen, die Sie brauchen, um Dateien umzubenennen und zu lBschen. Beispiel 1-27: Verwendung des Moduls os zum Umbenennen und LGschen von Dateien File: os-example-3.py import os import string def replace(file, search_for, replace_with): # ersetze Strings in einer Text-Datei back = os.path.splitext(file)[0] + ".bak" temp = os.path.splitext(file)[0] + ".tmp" try: # loesche alte temporaere Datei, falls vorhanden os.remove(temp) except os.error: pass
21
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-27: Verwendung des Moduls os zum Umbenennen und LGschen von Dateien (Fortsetzung) fi = open(file) fo = open(temp, "w") for s in fi.readlines(): fo.write(string.replace(s, search_for, replace_with)) fi.close() fo.close() try: # loesche alte Sicherungskopie, falls vorhanden os.remove(back) except os.error: pass # Original in Sicherungskopie umbenennen... os.rename(file, back) # ...und die temporaere Datei zum Original os.rename(temp, file) # # probieren Sie es aus! file = "samples/sample.txt" replace(file, "hello", "tjena") replace(file, "tjena", "hello")
Arbeiten mit Verzeichnissen Das Modul os enth;lt auch viele Funktionen, die auf ganze Verzeichnisse angewendet werden kBnnen. Die Funktion listdir gibt eine Liste aller Dateinamen eines bestimmten Verzeichnisses zurck, wie in Beispiel 1-28 gezeigt. Die unter Unix und Windows verwendeten Bezeichnungen fr das aktuelle und das Elternverzeichnis (. und ..) sind in dieser Liste nicht enthalten. Beispiel 1-28: Verwendung des Moduls os zum Auflisten der Dateien in einem Verzeichnis File: os-example-5.py import os for file in os.listdir("samples"): print file sample.au
22
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os Beispiel 1-28: Verwendung des Moduls os zum Auflisten der Dateien in einem Verzeichnis (Fortsetzung) sample.jpg sample.wav ...
Die Funktionen getcwd und chdir werden verwendet, um das aktuelle Verzeichnis zu bestimmen und zu setzen, wie in Beispiel 1-29 gezeigt. Beispiel 1-29: Verwendung des Moduls os zum Wechseln des Arbeitsverzeichnisses File: os-example-4.py import os # wo sind wir? cwd = os.getcwd() print "1", cwd # gehe runter os.chdir("samples") print "2", os.getcwd() # gehe wieder rauf os.chdir(os.pardir) print "3", os.getcwd() 1 /ematter/librarybook 2 /ematter/librarybook/samples 3 /ematter/librarybook
Die Funktionen makedirs und removedirs werden verwendet, um Verzeichnisb;ume zu erzeugen und zu lBschen, wie in Beispiel 1-30 gezeigt. Beispiel 1-30: Verwendung des Moduls os zum Erstellen und LGschen von mehreren Verzeichnisebenen File: os-example-6.py import os os.makedirs("test/multiple/levels") fp = open("test/multiple/levels/file", "w") fp.write("Inspector Praline") fp.close() # loesche die Datei os.remove("test/multiple/levels/file") # und alle leeren Verzeichnisse darueber os.removedirs("test/multiple/levels")
23
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beachten Sie, daß removedirs alle leeren Verzeichnisse entlang des angegebenen Pfads lBscht, beginnend mit dem letzten Verzeichnis im angegebenen Pfadnamen. Im Gegensatz dazu kBnnen die Funktionen mkdir und rmdir nur mit einer einzigen Verzeichnisebene umgehen, wie in Beispiel 1-31 gezeigt. Beispiel 1-31: Verwendung des Moduls os zum Erstellen und LGschen von Verzeichnissen File: os-example-7.py import os os.mkdir("test") os.rmdir("test") os.rmdir("samples") # wird fehlschlagen Traceback (innermost last): File "os-example-7", line 6, in ? OSError: [Errno 41] Directory not empty: 'samples'
Um nicht-leere Verzeichnisse zu lBschen, kBnnen Sie die Funktion rmtree des Moduls shutil benutzen.
Arbeiten mit Dateiattributen Die Funktion stat tr;gt Informationen ber eine existierende Datei zusammen, wie in Beispiel 1-32 gezeigt. Sie gibt ein 9-Tupel zurck, das die GrBße, den Zeitstempel der Onderung des Inode, den Modifikationszeitstempel und die Zugriffsrechte enth;lt. Beispiel 1-32: Verwendung des Moduls os, um Informationen 6ber eine Datei zu erhalten File: os-example-1.py import os import time file = "samples/sample.jpg" def dump(st): mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime = st print "- Groesse:", size, "bytes" print "- Besitzer:", uid, gid print "- Erstellungsdatum:", time.ctime(ctime) print "- Letzter Zugriff:", time.ctime(atime) print "- Letzte Modifikation:", time.ctime(mtime) print "- Modus:", oct(mode) print "- inode/dev:", ino, dev
24
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os Beispiel 1-32: Verwendung des Moduls os, um Informationen 6ber eine Datei zu erhalten (Fortsetzung) # # hole Stats-Werte zu einem Dateinamen st = os.stat(file) print "stat", file dump(st) print # # hole Stats-Werte zu einer geoeffneten Datei fp = open(file) st = os.fstat(fp.fileno()) print "fstat", file dump(st) stat samples/sample.jpg - Groesse: 4762 bytes - Besitzer: 0 0 - Erstellungsdatum: Tue Sep 07 22:45:58 1999 - Letzter Zugriff: Sun Sep 19 00:00:00 1999 - Letzte Modifikation: Sun May 19 01:42:16 1996 - Modus: 0100666 - inode/dev: 0 2 fstat samples/sample.jpg - Groesse: 4762 bytes - Besitzer: 0 0 - Erstellungsdatum: Tue Sep 07 22:45:58 1999 - Letzter Zugriff: Sun Sep 19 00:00:00 1999 - Letzte Modifikation: Sun May 19 01:42:16 1996 - Modus: 0100666 - inode/dev: 0 0
Einige Felder machen nur auf Unix-Plattformen Sinn. So kann mit dem Tupel (inode, dev) unter Unix eindeutig die Identit;t einer Datei bestimmt werden. Auf anderen Plattformen jedoch kann es beliebige Daten enthalten. Das Modul stat enth;lt eine Reihe ntzlicher Konstanten und Hilfsfunktionen fr das Arbeiten mit den Elementen des stat-Tupels. Einige davon werden in den folgenden Beispielen vorgestellt. Sie kBnnen die Modus- und Zeitfelder mit den Funktionen chmod und utime ;ndern, wie in Beispiel 1-33 gezeigt.
25
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-33: Verwendung des Moduls os zum Kndern von Rechten und Zeitstempeln einer Datei File: os-example-2.py import os import stat, time infile = "samples/sample.jpg" outfile = "out.jpg" # kopiere Inhalt fi = open(infile, "rb") fo = open(outfile, "wb") while 1: s = fi.read(10000) if not s: break fo.write(s) fi.close() fo.close() # kopiere Modus und Zeitstempel st = os.stat(infile) os.chmod(outfile, stat.S_IMODE(st[stat.ST_MODE])) os.utime(outfile, (st[stat.ST_ATIME], st[stat.ST_MTIME])) print print print print
"original", "=>" "modus", oct(stat.S_IMODE(st[stat.ST_MODE])) "atime", time.ctime(st[stat.ST_ATIME]) "mtime", time.ctime(st[stat.ST_MTIME])
print "kopie", "=>" st = os.stat(outfile) print "modus", oct(stat.S_IMODE(st[stat.ST_MODE])) print "atime", time.ctime(st[stat.ST_ATIME]) print "mtime", time.ctime(st[stat.ST_MTIME]) original => modus 0666 atime Thu Oct mtime Mon Nov kopie => modus 0666 atime Thu Oct mtime Mon Nov
26
14 15:15:50 1999 13 15:42:36 1995
14 15:15:50 1999 13 15:42:36 1995
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os
Arbeiten mit Prozessen Die Funktion system startet einen neuen Befehl im aktuellen Prozeß, und wartet darauf, daß er beendet wird, wie in Beispiel 1-34 gezeigt. Beispiel 1-34: Verwendung des Moduls os zur Ausf6hrung eines Betriebssystembefehls File: os-example-8.py import os if os.name == "nt": command = "dir" else: command = "ls -l" os.system(command) -rwxrw-r--rwxrw-r--rwxrw-r--rwxrw-r-...
1 1 1 1
effbot effbot effbot effbot
effbot effbot effbot effbot
76 1727 314 259
Oct Oct Oct Oct
9 7 7 7
14:17 19:00 20:29 20:38
README SimpleAsyncHTTP.py aifc-example-1.py anydbm-example-1.py
Der Befehl wird ber die Standard-Shell des Betriebssystems ausgefhrt und gibt den Exit-Status der Shell zurck. Unter Windows 95/98 ist die Shell normalerweise command. com, dessen Exit-Status immer 0 ist.
Da os.system den Befehl unver;ndert an die Shell weitergibt, kann es gef;hrlich sein, diese Funktion zu benutzen, ohne die Argumente genau zu prfen (stellen Sie sich vor, os.system("viewer %s" % file) auszufhren, wobei die Dateivariable auf "sample.jpg; rm -rf $HOME" gesetzt ist). Wenn Sie nicht sicher sind, ist es besser, statt dessen exec oder spawn auszufhren (wird sp;ter erkl;rt).
Die Funktion exec startet einen neuen Prozeß, der den aktuellen ersetzt (mit anderen Worten, »den Prozeß wechselt«). Beachten Sie, daß in Beispiel 1-35 die Meldung »Auf Wiedersehen« nie ausgegeben wird. Beispiel 1-35: Verwendung des Moduls os zum Starten eines neuen Prozesses File: os-exec-example-1.py import os import sys program = "python" arguments = ["hello.py"]
27
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-35: Verwendung des Moduls os zum Starten eines neuen Prozesses (Fortsetzung) print os.execvp(program, (program,) + tuple(arguments)) print "Tschuess" Nachmals Hallo und willkommen zur Show
Python verfgt ber eine ganze Menge von exec-Funktionen, die sich alle leicht unterschiedlich verhalten. Beispiel 1-35 verwendet execvp, das im Standardpfad nach dem Programm sucht, die Inhalte des zweiten Argument-Tupels als individuelle Argumente an das Programm bergibt und es mit den aktuellen Umgebungsvariablen startet. Informationen zu den anderen sieben MBglichkeiten, diese Funktion aufzurufen, finden Sie in der Python-Bibliotheksreferenz. Unter Unix kBnnen Sie andere Programme aus dem aktuellen Programm heraus aufrufen, indem Sie exec mit zwei weiteren Funktionen, fork und wait, kombinieren, wie in Beispiel 1-36 gezeigt. Die Funktion fork macht eine Kopie des aktuellen Prozesses, und die Funktion wait wartet, bis ein Kindprozeß endet. Beispiel 1-36: Verwendung des Moduls os zum Starten eines anderen Programms (Unix) File: os-exec-example-2.py import os import sys def run(program, *args): pid = os.fork() if not pid: os.execvp(program, (program,) + args) return os.wait()[0] run("python", "hello.py") print "Tschuess" Nochmals Hallo und willkommen zur Show Tschuess fork gibt null im neuen Prozeß zurck (die Rckgabe eines Wertes durch fork ist das
erste, was in diesem Prozeß passiert!) und eine von null verschiedene Prozeß-ID im Originalprozeß. Mit anderen Worten, not pid ist nur dann wahr, wenn wir uns im neuen Prozeß befinden. Die Funktionen fork und wait sind unter Windows nicht verfgbar, aber Sie kBnnen statt dessen die Funktion spawn benutzen, wie in Beispiel 1-37 gezeigt. Leider gibt es keine Standardversion von spawn, die im Pfad nach einer ausfhrbaren Datei sucht, d.h., Sie mssen das selbst tun.
28
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os Beispiel 1-37: Verwendung des Moduls os zum Starten eines anderen Programms (Windows) File: os-spawn-example-1.py import os import string def run(program, *args): # finde ausfuehrbares Programm for path in string.split(os.environ["PATH"], os.pathsep): file = os.path.join(path, program) + ".exe" try: return os.spawnv(os.P_WAIT, file, (file,) + args) except os.error: pass raise os.error, "ausfuehrbares Programm nicht gefunden" run("python", "hello.py") print "Tschuess" Nochmals Hallo und willkommen zur Show Tschuess
Sie kBnnen spawn auch benutzen, um andere Programme im Hintergrund auszufhren. Beispiel 1-38 fgt ein optionales Argument mode zur Funktion run hinzu. Wenn es auf os.P_NOWAIT gesetzt ist, wartet das Skript nicht darauf, daß das andere Programm beendet wird. Der voreingestellte Wert os.P_WAIT sagt spawn, daß es warten soll, bis der neue Prozeß beendet wird. Andere Werte sind z.B. os.P_OVERLAY, mit dem sich spawn wie exec verh;lt, und os.P_DETACH, mit dem der neue Prozeß im Hintergrund gestartet wird, losgelBst von der Konsole wie auch von der Tastatur. Beispiel 1-38: Verwendung des Moduls os zum Start eines anderen Programms im Hintergrund (Windows) File: os-spawn-example-2.py import os import string def run(program, *args, **kw): # finde ausfuehrbares Programm mode = kw.get("mode", os.P_WAIT) for path in string.split(os.environ["PATH"], os.pathsep): file = os.path.join(path, program) + ".exe" try: return os.spawnv(mode, file, (file,) + args) except os.error: pass raise os.error, "ausfuehrbares Programm nicht gefunden"
29
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-38: Verwendung des Moduls os zum Start eines anderen Programms im Hintergrund (Windows) (Fortsetzung) run("python", "hello.py", mode=os.P_NOWAIT) print "Tschuess" Tschuess Nochmals Hallo und willkommen zur Show
Beispiel 1-39 enth;lt eine spawn-Methode, die auf beiden Plattformen funktioniert. Beispiel 1-39: Verwendung von spawn oder fork/exec zum Starten eines anderen Programms File: os-spawn-example-3.py import os import string if os.name in ("nt", "dos"): exefile = ".exe" else: exefile = "" def spawn(program, *args): try: # pruefe, ob das Modul os eine Abkuerzung kennt return os.spawnvp(program, (program,) + args) except AttributeError: pass try: spawnv = os.spawnv except AttributeError: # nimm an, es ist Unix pid = os.fork() if not pid: os.execvp(program, (program,) + args) return os.wait()[0] else: # spawnv existiert, aber spawnp nicht: # suche ein ausfuehrbares Programm for path in string.split(os.environ["PATH"], os.pathsep): file = os.path.join(path, program) + exefile try: return spawnv(os.P_WAIT, file, (file,) + args) except os.error: pass raise IOError, "ausfuehrbares Programm nicht gefunden" # # probieren wir es aus! spawn("python", "hello.py")
30
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os Beispiel 1-39: Verwendung von spawn oder fork/exec zum Starten eines anderen Programms (Fortsetzung) print "Tschuess" Nochmals Hallo und willkommen zur Show Tschuess
Beispiel 1-39 versucht zuerst, eine Funktion namens spawnvp aufzurufen. Falls diese nicht existiert (also in 2.0 und frher), sucht die Funktion nach einer Funktion namens spawnv und sucht eigenst;ndig den Pfad ab. Als letzten Ausweg werden exec und fork benutzt.
Arbeiten mit Daemon-Prozessen Unter Unix kBnnen Sie mit fork auch den aktuellen Prozeß in einen Hintergrundprozeß (einen »Daemon«) umwandeln. Im Prinzip muß man mit fork eine Kopie des aktuellen Prozesses anfertigen und den ursprnglichen Prozeß beenden, so wie es in Beispiel 1-40 gezeigt wird. Beispiel 1-40: Verwendung des Moduls os zum Starten als Daemon (Unix) File: os-example-14.py import os import time pid = os.fork() if pid: os._exit(0) # beende Original print "Daemon gestartet" time.sleep(10) print "Daemon beendet"
Um einen echten Daemon zu erzeugen, muß man jedoch etwas mehr Arbeit investieren. Zuerst rufen Sie setpgrp auf, um den neuen Prozeß zu einem »process group leader« zu machen. Sonst kBnnten Signale, die an eine (zu dem Zeitpunkt) unbeteiligte Prozeßgruppe geschickt werden, zu Problemen in Ihrem Daemon fhren: os.setpgrp()
Es ist auch eine gute Idee, die Benutzermodusmaske zu lBschen, um sicherzustellen, daß vom Daemon erzeugte Dateien tats;chlich den vom Programm angegebenen Modus erhalten: os.umask(0)
31
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Dann sollten Sie die Dateien stdout/stderr umlenken, statt sie einfach zu schließen (wenn Sie das nicht tun, kBnnten Sie unerwartete Ausnahmen erhalten, sobald ein Teil Ihres Codes versucht, etwas ber stdout oder stderr auf die Konsole zu schreiben). class NullDevice: def write(self, s): pass sys.stdin.close() sys.stdout = NullDevice() sys.stderr = NullDevice()
Mit anderen Worten: W;hrend print in Python und printf/fprintf in C Ihr Programm nicht zum Absturz bringen werden, wenn die Ger;te abgekoppelt wurden, wird sys.stdout.write() frBhlich eine IOError -Ausnahme auslBsen, wenn die Anwendung als Daemon l;uft. Aber Ihr Programm arbeitet einwandfrei, wenn es im Vordergrund l;uft... $brigens, die in den vorherigen Beispielen verwendete Funktion _exit beendet den aktuellen Prozeß. Im Unterschied zu sys.exit funktioniert dies auch dann, wenn der Aufrufer die Ausnahme SystemExit abfangen sollte, wie in Beispiel 1-41 gezeigt. Beispiel 1-41: Verwendung des Moduls os zum Beenden des aktuellen Prozesses File: os-example-9.py import os import sys try: sys.exit(1) except SystemExit, value: print "abgefangen: exit(%s)" % value try: os._exit(2) except SystemExit, value: print "abgefangen: exit(%s)" % value print "bye!" abgefangen: exit(1)
Das Modul os.path Das Modul os.path enth;lt Funktionen, die auf verschiedene Weise mit langen Dateinamen (Pfadnamen) umgehen. Um dieses Modul zu benutzen, importiert man das Modul os und greift dann auf dieses Modul mit os.path zu.
32
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os.path
Arbeiten mit Dateinamen Das Modul os.path enth;lt eine Reihe von Funktionen, die mit langen Dateinamen in einer plattformunabh;ngigen Weise umgehen. Das bedeutet, Sie brauchen sich nicht um Vorw;rts- und Rckw;rtsschr;gstriche, Doppelpunkte und dergleichen zu kmmern. Betrachten wir Beispiel 1-42. Beispiel 1-42: Verwendung des Moduls os.path bei Dateinamen File: os-path-example-1.py import os filename = "mein/kleines/Pony" print print print print print print
"Plattform", os.name, "..." "split", "=>", os.path.split(filename) "splitext", "=>", os.path.splitext(filename) "dirname", "=>", os.path.dirname(filename) "basename", "=>", os.path.basename(filename) "join", "=>", os.path.join(os.path.dirname(filename), os.path.basename(filename))
Plattform nt ... split => ('mein/kleines', 'Pony') splitext => ('mein/kleines/Pony', '') dirname => mein/kleines basename => Pony join => mein/kleines\Pony
Man beachte, daß split nur ein einzelnes Element abspaltet. Das Modul os.path enth;lt auch eine Reihe von Funktionen, die es Ihnen ermBglichen, schnell herauszufinden, was ein Dateiname repr;sentiert, wie in Beispiel 1-43 gezeigt. Beispiel 1-43: Verwendung des Moduls os.path zur Pr6fung, was ein Dateiname reprBsentiert File: os-path-example-2.py import os FILES = ( os.curdir, "/", "file", "/file", "samples", "samples/sample.jpg", "directory/file", "../directory/file", "/directory/file" )
33
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-43: Verwendung des Moduls os.path zur Pr6fung, was ein Dateiname reprBsentiert (Fortsetzung) for file in FILES: print file, "=>", if os.path.exists(file): print "EXISTS", if os.path.isabs(file): print "ISABS", if os.path.isdir(file): print "ISDIR", if os.path.isfile(file): print "ISFILE", if os.path.islink(file): print "ISLINK", if os.path.ismount(file): print "ISMOUNT", print . => EXISTS ISDIR / => EXISTS ISABS ISDIR ISMOUNT file => /file => ISABS samples => EXISTS ISDIR samples/sample.jpg => EXISTS ISFILE directory/file => ../directory/file => /directory/file => ISABS
Die Funktion expanduser behandelt eine Abkrzung eines Benutzernamens genauso wie die meisten modernen Unix-Shells (sie funktioniert nicht sehr gut unter Windows), wie in Beispiel 1-44 gezeigt. Beispiel 1-44: Verwendung des Moduls os.path zum Einf6gen des Benutzernamens in einen Dateinamen File: os-path-expanduser-example-1.py import os print os.path.expanduser("~/.pythonrc") # /home/effbot/.pythonrc
Die Funktion expandvars fgt Umgebungsvariablen in einen Dateinamen ein, wie in Beispiel 1-45 gezeigt.
34
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os.path Beispiel 1-45: Verwendung des Moduls os.path zum Einf6gen von Variablen in einen Dateinamen File: os-path-expandvars-example-1.py import os os.environ["USER"] = "user" print os.path.expandvars("/home/$USER/config") print os.path.expandvars("$USER/folders") /home/user/config user/folders
Traversierung eines Dateisystems Die Funktion walk hilft Ihnen, alle Dateien in einem Verzeichnisbaum zu finden (wie Beispiel 1-46 demonstriert). Sie erwartet einen Verzeichnisnamen, eine Callback-Funktion und ein Datenobjekt, das an die Callback-Funktion weitergegeben wird. Beispiel 1-46: Verwendung des Moduls os.path zum Traversieren eines Dateisystems File: os-path-walk-example-1.py import os def callback(arg, directory, files): for file in files: print os.path.join(directory, file), repr(arg) os.path.walk(".", callback, "geheime Nachricht") ./aifc-example-1.py 'geheime Nachricht' ./anydbm-example-1.py 'geheime Nachricht' ./array-example-1.py 'geheime Nachricht' ... ./samples 'geheime Nachricht' ./samples/sample.jpg 'geheime Nachricht' ./samples/sample.txt 'geheime Nachricht' ./samples/sample.zip 'geheime Nachricht' ./samples/articles 'geheime Nachricht' ./samples/articles/article-1.txt 'geheime Nachricht' ./samples/articles/article-2.txt 'geheime Nachricht' ...
Die Funktion walk hat eine etwas obskure Benutzerschnittstelle (vielleicht liegt es an mir, aber ich kann mich nie an die Reihenfolge der Argumente erinnern). Die Funktion index in Beispiel 1-47 gibt statt dessen eine Liste von Dateinamen zurck, was es Ihnen ermBglicht, die Dateien mit einer einfachen for-in-Schleife zu bearbeiten.
35
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-47: Verwendung von os.listdir zum Traversieren eines Dateisystems File: os-path-walk-example-2.py import os def index(directory): # wie os.listdir, traversiert jedoch Verzeichnisbaeume stack = [directory] files = [] while stack: directory = stack.pop() for file in os.listdir(directory): fullname = os.path.join(directory, file) files.append(fullname) if os.path.isdir(fullname) and not os.path.islink(fullname): stack.append(fullname) return files for file in index("."): print file .\aifc-example-1.py .\anydbm-example-1.py .\array-example-1.py ...
Wenn Sie nicht alle Dateien auflisten mBchten (aus Performanz- oder Speichergrnden), Beispiel 1-48 zeigt einen anderen Ansatz. Hierbei verh;lt sich die Klasse DirectoryWalker wie ein Sequenzobjekt, das jeweils eine Datei zurckgibt: Beispiel 1-48: Verwendung von DirectoryWalker zum Traversieren eines Dateisystems File: os-path-walk-example-3.py import os class DirectoryWalker: # ein Vorwaerts-Iterator, der einen Verzeichnisbaum traversiert def __init__(self, directory): self.stack = [directory] self.files = [] self.index = 0 def __getitem__(self, index): while 1: try: file = self.files[self.index] self.index = self.index + 1 except IndexError: # pop-Operation auf dem Verzeichnis-Stapel self.directory = self.stack.pop()
36
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul os.path Beispiel 1-48: Verwendung von DirectoryWalker zum Traversieren eines Dateisystems (Fortsetzung) self.files = os.listdir(self.directory) self.index = 0 else: # wir haben einen Dateinamen fullname = os.path.join(self.directory, file) if os.path.isdir(fullname) and not os.path.islink(fullname): self.stack.append(fullname) return fullname for file in DirectoryWalker("."): print file .\aifc-example-1.py .\anydbm-example-1.py .\array-example-1.py ...
Beachten Sie, daß die Klasse DirectoryWalker den Index, der an die Methode _ _getitem_ _ bergeben wird, nicht prft. Das bedeutet, daß sie nicht korrekt funktionieren wird, wenn Sie die Elemente der Sequenz in einer anderen Reihenfolge bearbeiten. Und wenn Sie schließlich an den DateigrBßen oder ihren Zeitstempeln interessiert sind, zeigt Beispiel 1-49 eine Version der Klasse, die sowohl den Dateinamen zurckgibt als auch das von os.stat zurckgegebene Tupel. Diese Version kommt fr jede Datei mit ein oder zwei stat-Aufrufen weniger aus (sowohl os.path.isdir als auch os.path. islink verwenden stat) und l;uft auf einigen Plattformen ein ganzes Stck schneller. Beispiel 1-49: Verwendung von DirectoryStatWalker zum Traversieren eines Dateisystems File: os-path-walk-example-4.py import os, stat class DirectoryStatWalker: # ein Vorwaerts-Iterator, der einen Verzeichnisbaum traversiert # und Dateinamen und weitere Informationen zurueckgibt def __init__(self, directory): self.stack = [directory] self.files = [] self.index = 0 def __getitem__(self, index): while 1: try: file = self.files[self.index] self.index = self.index + 1
37
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-49: Verwendung von DirectoryStatWalker zum Traversieren eines Dateisystems (Fortsetzung) except IndexError: # pop-Operation auf dem Verzeichnis-Stapel self.directory = self.stack.pop() self.files = os.listdir(self.directory) self.index = 0 else: # wir haben einen Dateinamen fullname = os.path.join(self.directory, file) st = os.stat(fullname) mode = st[stat.ST_MODE] if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode): self.stack.append(fullname) return fullname, st for file, st in DirectoryStatWalker("."): print file, st[stat.ST_SIZE] .\aifc-example-1.py 336 .\anydbm-example-1.py 244 .\array-example-1.py 526
Das Modul stat Das in Beispiel 1-50 gezeigte Modul stat enth;lt eine Reihe von Konstanten und Testfunktionen, die mit der Funktion os.stat verwendet werden kBnnen. Beispiel 1-50: Verwendung des Moduls stat File: stat-example-1.py import stat import os, time st = os.stat("samples/sample.txt") print "Modus", "=>", oct(stat.S_IMODE(st[stat.ST_MODE])) print "Typ", "=>", if stat.S_ISDIR(st[stat.ST_MODE]): print "VERZEICHNIS", if stat.S_ISREG(st[stat.ST_MODE]): print "REGULAER", if stat.S_ISLNK(st[stat.ST_MODE]): print "LINK", print print "Groesse", "=>", st[stat.ST_SIZE]
38
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul string Beispiel 1-50: Verwendung des Moduls stat (Fortsetzung) print "letzter Zugriff ", "=>", time.ctime(st[stat.ST_ATIME]) print "letzte Aenderung", "=>", time.ctime(st[stat.ST_MTIME]) print "Inode-Aenderung ", "=>", time.ctime(st[stat.ST_CTIME]) Modus => 0664 Typ => REGULAER Groesse => 305 letzter Zugriff => Sun Oct 10 22:12:30 1999 letzte Aenderung => Sun Oct 10 18:39:37 1999 Inode-Aenderung => Sun Oct 10 15:26:38 1999
Das Modul string Das Modul string enth;lt eine Reihe von Funktionen zur Bearbeitung normaler Python-Strings, wie in Beispiel 1-51 gezeigt. Beispiel 1-51: Verwendung des Moduls string File: string-example-1.py import string text = "Monty Python's Flying Circus" print print print print print print print
"upper", "=>", string.upper(text) "lower", "=>", string.lower(text) "split", "=>", string.split(text) "join", "=>", string.join(string.split(text), "+") "replace", "=>", string.replace(text, "Python", "Java") "find", "=>", string.find(text, "Python"), string.find(text, "Java") "count", "=>", string.count(text, "n")
upper => MONTY PYTHON'S FLYING CIRCUS lower => monty python's flying circus split => ['Monty', "Python's", 'Flying', 'Circus'] join => Monty+Python's+Flying+Circus replace => Monty Java's Flying Circus find => 6 -1 count => 3
In Python 1.5.2 und vorher benutzt das Modul string – wann immer mBglich – Funktionen aus dem Implementierungsmodul strop. Ab Python 1.6 stehen die meisten Stringoperationen auch als Stringmethoden zur Verfgung, wie in Beispiel 1-52 gezeigt. Viele der Funktionen im Modul string sind einfach Hllfunktionen (Wrapper), die die entsprechende Stringmethode aufrufen.
39
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-52: Verwendung von Stringmethoden anstelle von Funktionen des Moduls string File: string-example-2.py text = "Monty Python's Flying Circus" print print print print print print print
"upper", "=>", text.upper() "lower", "=>", text.lower() "split", "=>", text.split() "join", "=>", "+".join(text.split()) "replace", "=>", text.replace("Python", "Perl") "find", "=>", text.find("Python"), text.find("Perl") "count", "=>", text.count("n")
upper => MONTY PYTHON'S FLYING CIRCUS lower => monty python's flying circus split => ['Monty', "Python's", 'Flying', 'Circus'] join => Monty+Python's+Flying+Circus replace => Monty Perl's Flying Circus find => 6 -1 count => 3
Zus;tzlich zu den F;higkeiten der Stringbearbeitung enth;lt das Modul string auch eine Reihe von Funktionen, die Strings in andere Datentypen konvertieren (wie in Beispiel 1-53 gezeigt). Beispiel 1-53: Verwendung des Moduls string zur Umwandlung von Strings in Zahlen File: string-example-3.py import string print print print print print
int("4711"), string.atoi("4711"), string.atoi("11147", 8), # oktal string.atoi("1267", 16), # hexadezimal string.atoi("3mv", 36) # was auch immer...
print string.atoi("4711", 0), print string.atoi("04711", 0), print string.atoi("0x4711", 0) print float("4711"), print string.atof("1"), print string.atof("1.23e5") 4711 4711 4711 4711 4711 4711 2505 18193 4711.0 1.0 123000.0
40
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul re In den meisten F;llen (vor allem, wenn Sie Version 1.6 oder sp;ter verwenden) kBnnen Sie die Funktionen int und float statt deren Entsprechungen im string-Modul verwenden. Die Funktion atoi erwartet ein optionales zweites Argument, das die Basiszahl angibt. Falls die Basis 0 ist, betrachtet die Funktion die ersten paar Bytes , bevor sie versucht, den Wert zu interpretieren: Bei »0x« wird die Basis auf 16 gesetzt (hexadezimal) und bei »0« auf 8 (oktal). Der Voreinstellungswert ist die Basis 10 (dezimal), als ob Sie kein zus;tzliches Argument angegeben h;tten. In 1.6 und sp;ter akzeptiert int auch ein zweites Argument, ebenso wie atoi. Im Gegensatz zu den Stringversionen akzeptieren int und float auch Unicode-Strings.
Das Modul re »Some people, when confronted with a problem, think ‘I know, I’ll use regular expressions.’ Now they have two problems.« – Jamie Zawinski, in comp.lang.emacs
Das Modul re bietet eine Reihe von m;chtigen F;higkeiten regul;re Ausdrcke betreffend, die es Ihnen ermBglichen, schnell nachzuprfen, ob ein gegebener String mit einem Muster 6bereinstimmt (mit Hilfe der Funktion match) oder ein solches Muster enthBlt (mit der Funktion search). Ein regul;rer Ausdruck ist ein Stringmuster, das in einer sehr kompakten (und ziemlich kryptischen) Syntax geschrieben ist. Die Funktion match versucht, dort, wo der String beginnt, einen Mustervergleich vorzunehmen, wie in Beispiel 1-54 gezeigt. Falls das Muster berhaupt mit irgend etwas bereinstimmt (inklusive einem leeren String, falls das Muster es erlaubt!), gibt match ein Vergleichsobjekt zurck. Die Methode group kann verwendet werden, um herauszufinden, worin die $bereinstimmung besteht. Beispiel 1-54: Verwendung des Moduls re zum Vergleichen von Strings File: re-example-1.py import re text = "Die Harald Schmidt-Show" # ein einzelnes Zeichen m = re.match(".", text) if m: print repr("."), "=>", repr(m.group(0)) # eine beliebige Zeichenkette m = re.match(".*", text) if m: print repr(".*"), "=>", repr(m.group(0))
41
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-54: Verwendung des Moduls re zum Vergleichen von Strings (Fortsetzung) # ein String aus Buchstaben (mindestens einer) m = re.match("\w+", text) if m: print repr("\w+"), "=>", repr(m.group(0)) # ein String aus Ziffern m = re.match("\d+", text) if m: print repr("\d+"), "=>", repr(m.group(0)) '.' => 'D' '.*' => 'Die Harald Schmidt-Show' '\\w+' => 'Die'
Sie kBnnen runde Klammern verwenden, um Abschnitte im Muster zu markieren. Falls eine $bereinstimmung erzielt wird, kBnnen mit der Methode group die Inhalte dieser Abschnitte, wie in Beispiel 1-55 gezeigt, ermittelt werden. group(1) gibt den Inhalt der ersten Gruppe zurck, group(2) den der zweiten usw. Wenn Sie mehrere Gruppenzahlen an die Funktion group bergeben, gibt sie ein Tupel zurck. Beispiel 1-55: Verwendung des Moduls re zum Finden passender Teilstrings File: re-example-2.py import re text = "10/15/99" m = re.match("(\d{2})/(\d{2})/(\d{2,4})", text) if m: print m.group(1, 2, 3) ('10', '15', '99')
Die Funktion search sucht innerhalb des Strings nach dem Muster, wie in Beispiel 1-56 gezeigt. Im wesentlichen probiert sie das Muster an jeder mBglichen Stelle des Strings aus, von links nach rechts, und gibt ein Vergleichsobjekt zurck, sobald sie eine $bereinstimmung feststellt. Falls das Muster nirgendwo paßt, gibt sie None zurck. Beispiel 1-56: Verwendung des Moduls re zur Suche nach Teilstrings File: re-example-3.py import re text = "Beispiel 3: Es gibt ein Datum 10/25/95 hier drin!" m = re.search("(\d{1,2})/(\d{1,2})/(\d{2,4})", text) print m.group(1), m.group(2), m.group(3)
42
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul re Beispiel 1-56: Verwendung des Moduls re zur Suche nach Teilstrings (Fortsetzung) month, day, year = m.group(1, 2, 3) print month, day, year date = m.group(0) print date 10 25 95 10 25 95 10/25/95
Mit der in Beispiel 1-57 verwendeten Funktion sub kBnnen Muster durch einen anderen String ersetzt werden. Beispiel 1-57: Verwendung des Moduls re zum Ersetzen von Teilstrings File: re-example-4.py import re text = "das ist nicht mehr lustig..." # Ersetzen von Literalen (string.replace ist schneller) print re.sub("lustig", "unterhaltsam", text) # verdichte alle Sequenzen von Nicht-Buchstaben # auf ein einzelnes Minus print re.sub("[^\w]+", "-", text) # wandle alle Woerter in Pieps um print re.sub("\S+", "-PIEP-", text) das ist nicht mehr unterhaltsam... das-ist-nicht-mehr-lustig-PIEP- -PIEP- -PIEP- -PIEP- -PIEP-
Sie kBnnen sub auch dazu verwenden, Muster mit Hilfe einer callback-Funktion zu ersetzen. Beispiel 1-58 zeigt, wie Muster vorkompiliert werden. Beispiel 1-58: Verwendung des Moduls re zum Ersetzen von Teilstrings mit der callback-Funktion File: re-example-5.py import re import string text = "eine Zeile Text\012eine weitere Zeile Text\012etc..." def octal(match): # ersetze Oktal-Code durch entsprechendes ASCII-Zeichen return chr(string.atoi(match.group(1), 8))
43
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-58: Verwendung des Moduls re zum Ersetzen von Teilstrings mit der callback-Funktion (Fortsetzung) octal_pattern = re.compile(r"\\(\d\d\d)") print text print octal_pattern.sub(octal, text) eine Zeile Text eine weitere Zeile Text etc... eine Zeile Text eine weitere Zeile Text etc...
Ohne eine Kompilierung tr;gt das Modul re kompilierte Versionen in einen Cache-Speicher fr Sie ein, d.h., Sie mssen normalerweise regul;re Ausdrcke in kleinen Skripten nicht kompilieren. Bei Python 1.5.2 umfaßt dieser Cache-Speicher 20 Muster. Bei 2.0 wurde seine GrBße auf 100 Muster erhBht. Schließlich wird in Beispiel 1-59 ein String mit einer Liste von Mustern verglichen. Diese Muster werden zu einem einzigen Muster zusammengefaßt und vorkompiliert, um Zeit zu sparen. Beispiel 1-59: Verwendung des Moduls re zum Vergleich mit einem von vielen Mustern File: re-example-6.py import re, string def combined_pattern(patterns): p = re.compile( string.join(map(lambda x: "("+x+")", patterns), "|") ) def fixup(v, m=p.match, r=range(0,len(patterns))): try: regs = m(v).regs except AttributeError: return None # kein Match, also versagt m.regs else: for i in r: if regs[i+1] != (-1, -1): return i return fixup # # ausprobieren! patterns = [ r"\d+", r"abc\d{2,4}", r"p\w+" ]
44
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul math Beispiel 1-59: Verwendung des Moduls re zum Vergleich mit einem von vielen Mustern (Fortsetzung) p = combined_pattern(patterns) print print print print print print
p("129391") p("abc800") p("abc1600") p("python") p("perl") p("tcl")
0 1 1 2 2 None
Das Modul math Das Modul math implementiert eine Reihe von mathematischen Operationen fr Fließkommazahlen. Die Funktionen sind im allgemeinen dnne Hllen (Wrapper) um gleichnamige Funktionen der C-Bibliothek auf der entsprechenden Plattform. Daher kBnnen die Resultate zwischen verschiedenen Plattformen im Normalfall leicht und in Ausnahmef;llen erheblich variieren. Beispiel 1-60 zeigt die Verwendung des Moduls math. Beispiel 1-60: Verwendung des Moduls math File: math-example-1.py import math print "e", "=>", math.e print "pi", "=>", math.pi print "hypot", "=>", math.hypot(3.0, 4.0) # und viele andere... e => 2.71828182846 pi => 3.14159265359 hypot => 5.0
In der Python-Bibliotheksreferenz finden Sie eine vollst;ndige Liste aller Funktionen.
45
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule
Das Modul cmath Das in Beispiel 1-61 gezeigte Modul cmath enth;lt eine Reihe von mathematischen Operationen fr komplexe Zahlen. Beispiel 1-61: Verwendung des Moduls cmath File: cmath-example-1.py import cmath print "pi", "=>", cmath.pi print "sqrt(-1)", "=>", cmath.sqrt(-1) pi => 3.14159265359 sqrt(-1) => 1j
In der Python-Bibliotheksreferenz finden Sie eine vollst;ndige Liste aller Funktionen.
Das Modul operator Das Modul operator bietet eine »funktionale« Schnittstelle zu den Standardoperatoren in Python. Die Funktionen dieses Moduls kBnnen an Stelle einiger lambda-Konstrukte verwendet werden, wenn Daten mit Funktionen wie z.B. map und filter bearbeitet werden. Aus offensichtlichen Grnden sind sie auch ziemlich popul;r bei Leuten, die gerne obskuren Code schreiben. Das Modul operator wird in Beispiel 1-62 vorgestellt. Beispiel 1-62: Verwendung des Moduls operator File: operator-example-1.py import operator sequence = 1, 2, 4 print print print print print print print print
"add", "=>", reduce(operator.add, sequence) "sub", "=>", reduce(operator.sub, sequence) "mul", "=>", reduce(operator.mul, sequence) "concat", "=>", operator.concat("spam", "egg") "repeat", "=>", operator.repeat("spam", 5) "getitem", "=>", operator.getitem(sequence, 2) "indexOf", "=>", operator.indexOf(sequence, 2) "sequenceIncludes", "=>", operator.sequenceIncludes(sequence, 3)
add => sub => mul => concat repeat
46
7 -5 8 => spamegg => spamspamspamspamspam
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul operator Beispiel 1-62: Verwendung des Moduls operator (Fortsetzung) getitem => 4 indexOf => 1 sequenceIncludes => 0
Beispiel 1-63 zeigt einige Funktionen von operator, mit denen der Typ von Objekten berprft werden kann. Beispiel 1-63: Verwendung des Moduls operator zur Typ6berpr6fung File: operator-example-2.py import operator import UserList def dump(data): print type(data), "=>", if operator.isCallable(data): print "AUFRUFBAR", if operator.isMappingType(data): print "ABBILDUNG", if operator.isNumberType(data): print "ZAHL", if operator.isSequenceType(data): print "SEQUENZ", print dump(0) dump("string") dump("string"[0]) dump([1, 2, 3]) dump((1, 2, 3)) dump({"a": 1}) dump(len) # Funktion dump(UserList) # Modul dump(UserList.UserList) # Klasse dump(UserList.UserList()) # Instanz
'int'> => ZAHL 'string'> => SEQUENZ 'string'> => SEQUENZ 'list'> => SEQUENZ 'tuple'> => SEQUENZ 'dictionary'> => ABBILDUNG 'builtin_function_or_method'> => AUFRUFBAR 'module'> => 'class'> => AUFRUFBAR 'instance'> => ABBILDUNG ZAHL SEQUENZ
47
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Man beachte, daß das Modul operator Objektinstanzen nicht auf normale Weise behandelt. Seien Sie vorsichtig, wenn Sie die Funktionen isNumberType, isMappingType und isSequenceType benutzen. Es kann leicht passieren, daß Ihr Code unflexibler wird, als er eigentlich sein muß. Beachten Sie auch, daß ein Element einer Stringsequenz (ein Zeichen) ebenfalls eine Sequenz ist. Wenn Sie eine rekursive Funktion schreiben, die isSequenceType benutzt, um einen Objektbaum zu traversieren, bergeben Sie ihr besser keinen gewBhnlichen String (oder irgend etwas, das einen solchen enth;lt).
Das Modul copy Das Modul copy enth;lt zwei Funktionen, mit denen Objekte kopiert werden kBnnen, wie in Beispiel 1-64 gezeigt. copy(object) Þ object erzeugt eine »flache« Kopie eines gegebenen Objekts. In die-
sem Zusammenhang bedeutet flach, daß das Objekt selbst kopiert wird, daß sich aber, wenn das Objekt ein Container ist, die Elemente der Kopie noch immer auf die Originalelemente beziehen. Beispiel 1-64: Verwendung des Moduls copy zum Kopieren von Objekten File: copy-example-1.py import copy a = [[1],[2],[3]] b = copy.copy(a) print "vorher", "=>" print a print b # modifiziere Original a[0][0] = 0 a[1] = None print "nachher", "=>" print a print b vorher => [[1], [2], [3]] [[1], [2], [3]] nachher => [[0], None, [3]] [[0], [2], [3]]
48
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sys Sie kBnnen flache Kopien von Listen auch mit der Syntax [:] erzeugen (vollst;ndiger Teilbereich), und Sie kBnnen Kopien von Dictionaries mit Hilfe der Methode copy anfertigen. Im Gegensatz dazu erzeugt deepcopy(object) Þ object eine »tiefe« Kopie eines Objekts, wie in Beispiel 1-65 gezeigt. Falls das Objekt ein Container ist, werden alle Elemente rekursiv kopiert. Beispiel 1-65: Verwendung des Moduls copy zum Kopieren von Sammlungen File: copy-example-2.py import copy a = [[1],[2],[3]] b = copy.deepcopy(a) print "vorher", "=>" print a print b # modifiziere Original a[0][0] = 0 a[1] = None print "nachher", "=>" print a print b vorher => [[1], [2], [3]] [[1], [2], [3]] nachher => [[0], None, [3]] [[1], [2], [3]]
Das Modul sys Das Modul sys bietet eine Reihe von Funktionen und Variablen, mit denen verschiedene Teile der Laufzeitumgebung von Python bearbeitet werden kBnnen.
Arbeiten mit Kommandozeilenargumenten Die Liste argv enth;lt die Argumente, die an das Skript bergeben wurden, als der Interpreter gestartet wurde, wie in Beispiel 1-66 gezeigt. Das erste Element enth;lt den Namen des Skripts selbst.
49
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-66: Verwendung des Moduls sys f6r den Zugriff auf Skriptargumente File: sys-argv-example-1.py import sys print "Skriptname lautet", sys.argv[0] if len(sys.argv) > 1: print "Es gibt", len(sys.argv)-1, "Argumente:" for arg in sys.argv[1:]: print arg else: print "Es gibt keine Argumente!" Skriptname lautet sys-argv-example-1.py Es gibt keine Argumente!
Falls Sie das Skript von der Standardeingabe lesen (z.B. python < sys-argv-example-1. py), wird der Skriptname auf einen leeren String gesetzt. Falls Sie das Programm als String bergeben (mit der Option -c), wird der Skriptname auf -c gesetzt.
Arbeiten mit Modulen Die Liste path enth;lt eine Liste von Verzeichnisnamen, in denen Python nach Erweiterungsmodulen sucht (Module in Python-Quelltext, kompilierte Module oder bin;re Erweiterungen). Wenn Sie Python starten, wird diese Liste durch einen Mix aus eingebauten Regeln, dem Inhalt der Umgebungsvariable PYTHONPATH und (bei Windows) den Registerinhalten initialisiert. Aber da es eine gewBhnliche Liste ist, kBnnen Sie sie auch innerhalb des Programms bearbeiten, wie Beispiel 1-67 zeigt. Beispiel 1-67: Verwendung des Moduls sys zur Bearbeitung des Modulsuchpfads File: sys-path-example-1.py import sys print "Pfad hat", len(sys.path), "Elemente" # fuege das Verzeichnis samples zum Pfad hinzu sys.path.insert(0, "samples") import sample # vernichte den Pfad sys.path = [] import random # Huch! Pfad hat 7 Elemente Dies ist das Modul sample!
50
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sys Beispiel 1-67: Verwendung des Moduls sys zur Bearbeitung des Modulsuchpfads (Fortsetzung) Traceback (innermost last): File "sys-path-example-1.py", line 11, in ? import random # Huch! ImportError: No module named random
Beispiel 1-68 zeigt die Liste builtin_module_names, die die Namen aller Module enth;lt, die im Python-Interpreter eingebaut sind. Beispiel 1-68: Verwendung des Moduls sys zum Auffinden von eingebauten Modulen File: sys-builtin-module-names-example-1.py import sys def dump(module): print module, "=>", if module in sys.builtin_module_names: print "" else: module = __import__(module) print module.__file__ dump("os") dump("sys") dump("string") dump("strop") dump("zlib") os => C:\python\lib\os.pyc sys => string => C:\python\lib\string.pyc strop => zlib => C:\python\zlib.pyd
Das Dictionary modules enth;lt alle geladenen Module. Die Anweisung import prft dieses Dictionary, bevor sie tats;chlich etwas von der Festplatte l;dt. Wie Sie in Beispiel 1-69 sehen kBnnen, l;dt Python ziemlich viele Module, bevor es die Kontrolle an Ihr Skript bergibt. Beispiel 1-69: Verwendung des Moduls sys zum Auffinden importierter Module File: sys-modules-example-1.py import sys print sys.modules.keys() ['os.path', 'os', 'exceptions', '__main__', 'ntpath', 'strop', 'nt', 'sys', '__builtin__', 'site', 'signal', 'UserDict', 'string', 'stat']
51
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule
Arbeiten mit Referenzz#hlern Die in Beispiel 1-70 gezeigte Funktion getrefcount gibt den Referenzz;hler zu einem gegebenen Objekt zurck, d.h. die Anzahl aller Orte, wo die Variable benutzt wird. Python verwaltet diese Zahl, und sobald sie auf 0 f;llt, wird das Objekt zerstBrt. Beispiel 1-70: Verwendung des Moduls sys zum Auffinden des ReferenzzBhlers File: sys-getrefcount-example-1.py import sys variable = 1234 print sys.getrefcount(0) print sys.getrefcount(variable) print sys.getrefcount(None) 50 3 192
Man beachte, daß dieser Wert immer grBßer als die eigentliche Zahl ist, da die Funktion selbst auch auf das Objekt zugreift, w;hrend sie diesen Wert bestimmt.
1berpr7fung der Rechnerplattform In Beispiel 1-71 wird die Variable platform gezeigt, die den Namen der Rechnerplattform enth;lt. Beispiel 1-71: Verwendung des Moduls sys zur Bestimmung der aktuellen Plattform File: sys-platform-example-1.py import sys # # emuliere "import os.path" (gewissermassen)... if sys.platform == "win32": import ntpath pathmodule = ntpath elif sys.platform == "mac": import macpath pathmodule = macpath else: # nimm an, es ist eine Posix-Plattform import posixpath pathmodule = posixpath print pathmodule
52
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sys Typische Namen fr solche Plattformen sind win32 fr Windows 9X/NT und mac fr den Macintosh. Bei Unix-Systemen wird der Plattformname normalerweise von der Ausgabe des Befehls uname -r abgeleitet, z.B. irix6, linux2 oder sunos5 (Solaris).
Verfolgung des Programmablaufs Mit der Funktion setprofiler kBnnen Sie eine Profiler-Funktion installieren. Diese wird jedesmal aufgerufen, wenn eine Funktion oder Methode aufgerufen wird, ein Rckgabewert bergeben wird (explizit oder implizit) sowie fr jede Ausnahme. Sehen wir uns Beispiel 1-72 an. Beispiel 1-72: Verwendung des Moduls sys zur Installation einer Profiler-Funktion File: sys-setprofiler-example-1.py import sys def test(n): j = 0 for i in range(n): j = j + i return n def profiler(frame, event, arg): print event, frame.f_code.co_name, frame.f_lineno, "->", arg # Profiler ist ab naechstem Aufruf/Rueckgabe/Ausnahme aktiviert sys.setprofile(profiler) # messe diesen Aufruf test(1) # setze Profiler aus sys.setprofile(None) # messe diesen Aufruf nicht test(2) call test 3 -> None return test 7 -> 1
Das Modul profile stellt ein komplettes Profiler-Framework zur Verfgung, das auf dieser Funktion basiert. Die Funktion settrace in Beispiel 1-73 funktioniert ;hnlich, aber die Funktion trace wird fr jede neue Zeile aufgerufen.
53
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-73: Verwendung des Moduls sys zur Installation einer trace-Funktion File: sys-settrace-example-1.py import sys def test(n): j = 0 for i in range(n): j = j + i return n def tracer(frame, event, arg): print event, frame.f_code.co_name, frame.f_lineno, "->", arg return tracer # tracer ist ab naechstem Aufruf/Rueckgabe/Ausnahme aktiviert sys.settrace(tracer) # verfolge diesen Aufruf test(1) # setze Ablaufverfolgung aus sys.settrace(None) # verfolge diesen Aufruf nicht test(2) call test 3 line test 3 line test 4 line test 5 line test 5 line test 6 line test 5 line test 7 return test
-> None -> None -> None -> None -> None -> None -> None -> None 7 -> 1
Das Modul pdb stellt ein komplettes Debugging-Framework zur Verfgung, das auf den VerfolgungsmBglichkeiten basiert, die von dieser Funktion angeboten werden.
Arbeiten mit der Standardeingabe und -ausgabe Die Variablen stdin, stdout und stderr enthalten Strom-Objekte, die den StandardI/O-StrBmen entsprechen. Sie kBnnen direkt auf diese zugreifen, wenn Sie eine weitergehendere Kontrolle ber die Ausgabe brauchen, als Sie sie von print bekommen kBnnen. Sie kBnnen sie auch ersetzen, falls Sie die Ausgabe und Eingabe an ein anderes Ger;t umlenken oder sie in einer anderen, nicht standardm;ßigen Art verarbeiten wollen, wie in Beispiel 1-74 gezeigt.
54
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sys Beispiel 1-74: Verwendung des Moduls sys zur Umlenkung der Ausgabe File: sys-stdout-example-1.py import sys import string class Redirect: def __init__(self, stdout): self.stdout = stdout def write(self, s): self.stdout.write(string.lower(s)) # leite Standardausgabe um (inklusive der print-Anweisung) old_stdout = sys.stdout sys.stdout = Redirect(sys.stdout) print "HEJA SVERIGE", print "FRISKT HUM\R" # stelle Standardausgabe wieder her sys.stdout = old_stdout print "M]]]]L!" heja sverige friskt humTr MUUUUL!
Alles, was man braucht, um die Ausgabe umzulenken, ist ein Objekt, das die Methode write implementiert. (Außer es handelt sich um eine Instanz eines C-Datentyps: In diesem Falle benutzt Python ein ganzzahliges Attribut namens softspace, um den Abstand (engl. spacing) zu steuern, und fgt es dem Objekt hinzu, falls es nicht existiert. Sie mssen sich darum nicht kmmern, wenn Sie Python-Objekte verwenden, aber wenn Sie an einen C-Datentyp umleiten mssen, sollten Sie sicherstellen, daß der Datentyp das Attribut softspace untersttzt.)
Beendigung des Programms Wenn Sie das Ende des Hauptprogramms erreichen, wird der Interpreter automatisch beendet. Wenn Sie mittendrin herausspringen mssen, kBnnen Sie die Funktion sys. exit aufrufen, die eine optionale Ganzzahl erwartet, die an das aufrufende Programm bergeben wird. Das wird in Beispiel 1-75 gezeigt.
55
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-75: Verwendung des Moduls sys zum Beenden des Programms File: sys-exit-example-1.py import sys print "Hallo" sys.exit(1) print "ihr da" Hallo
Es mag nicht auf den ersten Blick zu erkennen sein, aber sys.exit beendet die Ausfhrung nicht sofort. Statt dessen lBst sie die Ausnahme SystemExit aus. Sie kBnnen also Aufrufe von sys.exit in Ihrem Hauptprogramm abfangen, wie Beispiel 1-76 zeigt. Beispiel 1-76: Abfangen des Aufrufs von sys.exit File: sys-exit-example-2.py import sys print "Hallo" try: sys.exit(1) except SystemExit: pass print "ihr da" Hallo ihr da
Wenn Sie selbst eine Aufr;umaktion vornehmen wollen, kBnnen Sie einen »Exit-Handler« installieren, also eine Funktion, die automatisch beim Beenden aufgerufen wird. Dies wird in Beispiel 1-77 gezeigt. Beispiel 1-77: Abfangen des Aufrufs von sys.exit auf eine andere Art File: sys-exitfunc-example-1.py import sys def exitfunc(): print "Welt" sys.exitfunc = exitfunc print "Hallo"
56
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul atexit Beispiel 1-77: Abfangen des Aufrufs von sys.exit auf eine andere Art (Fortsetzung) sys.exit(1) print "ihr da" # nie ausgegeben Hallo Welt
In Python 2.0 kBnnen Sie das Modul atexit verwenden, um mehr als einen Exit-Handler zu registrieren.
Das Modul atexit (nur 2.0) Das Modul atexit ermBglicht es, eine oder mehrere Funktionen zu registrieren, die aufgerufen werden, wenn der Interpreter beendet wird. Um eine Funktion zu registrieren rufen Sie einfach die Funktion register auf, wie in Beispiel 1-78 gezeigt. Sie kBnnnen auch ein oder mehrere zus;tzliche Argumente hinzufgen, die als Argumente an die Funktion exit bergeben werden. Beispiel 1-78: Verwendung des Moduls atexit File: atexit-example-1.py import atexit def exit(*args): print "exit", args # Registriere zwei Exit-Handler atexit.register(exit) atexit.register(exit, 1) atexit.register(exit, "Hallo", "Welt") exit ('Hallo', 'Welt') exit (1,) exit ()
Dieses Modul ist eine sehr einfache Hlle um die Funktion sys.exitfunc.
Das Modul time Das Modul time bietet eine Reihe von Funktionen, um mit Datums- und Zeitangaben eines Tages umzugehen. Es ist eine dnne Schicht um die C-Laufzeitbibliothek. Eine gegebene Datums- oder Zeitangabe kann entweder als Fließkommawert dargestellt werden (die Anzahl von Sekunden seit einem Bezugspunkt, normalerweise dem 1. Januar 1970) oder als ein Zeit-Tupel.
57
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule
Bestimmen der aktuellen Zeit Beispiel 1-79 zeigt, wie Sie das Modul time verwenden kBnnen, um die aktuelle Zeit zu erhalten. Beispiel 1-79: Verwendung des Moduls time zur Bestimmung der aktuellen Zeit File: time-example-1.py import time now = time.time() print print print print print
now, "Sekunden seit", time.gmtime(0)[:6] "oder mit anderen Worten:" "- Lokalzeit:", time.localtime(now) "- UTC:", time.gmtime(now)
937758359.77 Sekunden seit (1970, 1, 1, 0, 0, 0) oder mit anderen Worten: - Lokalzeit: (1999, 9, 19, 18, 25, 59, 6, 262, 1) - UTC: (1999, 9, 19, 16, 25, 59, 6, 262, 0)
Das von localtime und gmtime zurckgegebene Tupel enth;lt Jahr, Monat, Tag, Stunde, Minute, Sekunde, Wochentag, Jahrestag und eine Sommerzeitangabe. Die Jahreszahl besteht aus vier Ziffern, der Wochentag beginnt mit 0 fr Montag, und der 1. Januar hat als Jahrestag die Nummer 1.
Umwandlung von Zeitangaben in Strings Natrlich kBnnen Sie die standardm;ßigen String-Formatierungsoperatoren verwenden, um ein Zeit-Tupel in einen String umzuwandeln, aber das Modul time stellt eine Reihe von Standardfunktionen fr die Konvertierung bereit, wie Beispiel 1-80 zeigt. Beispiel 1-80: Verwendung des Moduls time zur Formatierung von Datums- und Zeitangaben File: time-example-2.py import time now = time.localtime(time.time()) print print print print print print
58
time.asctime(now) time.strftime("%y/%m/%d %H:%M", now) time.strftime("%a %b %d", now) time.strftime("%c", now) time.strftime("%I %p", now) time.strftime("%Y-%m-%d %H:%M:%S %Z", now)
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul time Beispiel 1-80: Verwendung des Moduls time zur Formatierung von Datums- und Zeitangaben (Fortsetzung) # von year, print print print
Hand... month, day, hour, minute, second, weekday, yearday, daylight = now "%04d-%02d-%02d" % (year, month, day) "%02d:%02d:%02d" % (hour, minute, second) ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")[weekday], yearday
Sun Jun 24 18:11:18 2001 01/06/24 18:11 Sun Jun 24 06/24/01 18:11:18 06 PM 2001-06-24 18:11:18 WesteuropWische Sommerzeit 2001-06-24 18:11:18 SUN 175
Umwandlung von Strings in Zeitangaben Auf einigen Plattformen enth;lt das Modul time die Funktion strptime, die so ziemlich das Gegenteil von strftime ist. Ausgehend von einem gegebenen String und einem Muster gibt sie das entsprechende Zeit-Tupel zurck, wie in Beispiel 1-81 gezeigt. Beispiel 1-81: Verwendung der Funktion time.strptime zum Parsen von Datums- und Zeitangaben File: time-example-6.py import time # sicherstellen, dass wir eine strptime-Funktion haben! try: strptime = time.strptime except AttributeError: from strptime import strptime print strptime("31 Nov 00", "%d %b %y") print strptime("1 Jan 70 1:30pm", "%d %b %y %I:%M%p")
Die Funktion time.strptime ist zur Zeit nur dann in Python verfgbar, wenn sie von den C-Bibliotheken der Plattform zur Verfgung gestellt wird. Fr Plattformen, die dafr keine Standardimplementierung haben (das trifft auch auf Windows zu), zeigt Beispiel 1-82 eine partielle LBsung.
59
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-82: Eine Implementierung von strptime File: strptime.py import re import string MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] SPEC = { # Abbildung, die Formatierungscodes auf Fragmente # eines regulaeren Ausdrucks abbildet "%a": "(?P<weekday>[a-z]+)", "%A": "(?P<weekday>[a-z]+)", "%b": "(?P<month>[a-z]+)", "%B": "(?P<month>[a-z]+)", "%C": "(?P\d\d?)", "%d": "(?P\d\d?)", "%D": "(?P<month>\d\d?)/(?P\d\d?)/(?P\d\d)", "%e": "(?P\d\d?)", "%h": "(?P<month>[a-z]+)", "%H": "(?P\d\d?)", "%I": "(?P\d\d?)", "%j": "(?P\d\d?\d?)", "%m": "(?P<month>\d\d?)", "%M": "(?P<minute>\d\d?)", "%p": "(?Pam|pm)", "%R": "(?P\d\d?):(?P<minute>\d\d?)", "%S": "(?P<second>\d\d?)", "%T": "(?P\d\d?):(?P<minute>\d\d?):(?P<second>\d\d?)", "%U": "(?P<week>\d\d)", "%w": "(?P<weekday>\d)", "%W": "(?P<weekday>\d\d)", "%y": "(?P\d\d)", "%Y": "(?P\d\d\d\d)", "%%": "%" } class TimeParser: def __init__(self, format): # wandle strptime-Formatstring in regulaeren Ausdruck format = string.join(re.split("(?:\s|%t|%n)+", format)) pattern = [] try: for spec in re.findall("%\w|%%|.", format): if spec[0] == "%": spec = SPEC[spec] pattern.append(spec) except KeyError: raise ValueError, "unbekannter Specifier: %s" % spec self.pattern = re.compile("(?i)" + string.join(pattern, ""))
60
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul time Beispiel 1-82: Eine Implementierung von strptime (Fortsetzung) def match(self, daytime): # erkenne Zeitstring match = self.pattern.match(daytime) if not match: raise ValueError, "Formatfehler" get = match.groupdict().get tm = [0] * 9 # extrahiere Datumselemente y = get("year") if y: y = int(y) if y < 68: y = 2000 + y elif y < 100: y = 1900 + y tm[0] = y m = get("month") if m: if m in MONTHS: m = MONTHS.index(m) + 1 tm[1] = int(m) d = get("day") if d: tm[2] = int(d) # extrahiere Zeitelemente h = get("hour") if h: tm[3] = int(h) else: h = get("hour12") if h: h = int(h) if string.lower(get("ampm12", "")) == "pm": h = h + 12 tm[3] = h m = get("minute") if m: tm[4] = int(m) s = get("second") if s: tm[5] = int(s) # ignoriere vorlaeufig Wochentag/Jahrestag return tuple(tm) def strptime(string, format="%a %b %d %H:%M:%S %Y"): return TimeParser(format).match(string) if __name__ == "__main__": # ausprobieren import time print strptime("2000-12-20 01:02:03", "%Y-%m-%d %H:%M:%S") print strptime(time.ctime(time.time()))
61
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-82: Eine Implementierung von strptime (Fortsetzung) (2000, 12, 20, 1, 2, 3, 0, 0, 0) (2000, 11, 15, 12, 30, 45, 0, 0, 0)
Umwandlung von Zeitangaben Die Umwandlung eines Zeit-Tupels zurck in einen Zeitwert ist ziemlich einfach, jedenfalls solange wir von lokaler Zeit sprechen. $bergeben Sie einfach das Zeit-Tupel an die Funktion mktime, wie in Beispiel 1-83 gezeigt. Beispiel 1-83: Verwendung des Moduls time zur Umwandlung eines lokalen Zeit-Tupels in einen Zeit-Integer File: time-example-3.py import time t0 = time.time() tm = time.localtime(t0) print tm print t0 print time.mktime(tm) (1999, 9, 9, 0, 11, 8, 3, 252, 1) 936828668.16 936828668.0
Unglcklicherweise gibt es in der Standardbibliothek zur Version 1.5.2 keine Funktion, die UTC-Zeit-Tupel in Zeitwerte zur6ckwandelt (weder in Python noch in den zugrundeliegenden C-Bibliotheken). Beispiel 1-84 zeigt eine Python-Implementierung einer solchen Funktion namens timegm. Beispiel 1-84: Umwandlung eines UTC-Zeit-Tupels in einen Zeit-Integer File: time-example-4.py import time def _d(y, m, d, days=(0,31,59,90,120,151,181,212,243,273,304,334,365)): # bildet ein Datum auf die Anzahl der Tage seit einem Bezugspunkt ab return (((y - 1901)*1461)/4 + days[m-1] + d + ((m > 2 and not y % 4 and (y % 100 or not y % 400)) and 1)) def timegm(tm, epoch=_d(1970,1,1)): year, month, day, h, m, s = tm[:6] assert year >= 1970 assert 1 <= month <= 12 return (_d(year, month, day) - epoch)*86400 + h*3600 + m*60 + s
62
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul time Beispiel 1-84: Umwandlung eines UTC-Zeit-Tupels in einen Zeit-Integer (Fortsetzung) t0 = time.time() tm = time.gmtime(t0) print tm print t0 print timegm(tm) (1999, 9, 8, 22, 12, 12, 2, 251, 0) 936828732.48 936828732
In Python 1.6 und sp;ter ist eine ;hnliche Funktion im Modul calendar unter dem Namen calendar.timegm verfgbar.
Zeitmessungen Mit dem Modul time kann die Ausfhrung eines Python-Programms zeitlich gemessen werden, wie in Beispiel 1-85 gezeigt. Sie kBnnen entweder »Echtzeit« (engl. wall time) oder »Prozeßzeit« (die Menge an CPU-Zeit, die der Prozeß bislang verbraucht hat) messen. Beispiel 1-85: Verwendung des Moduls time zur Laufzeitbestimmung eines Algorithmus File: time-example-5.py import time def procedure(): time.sleep(2.5) # messen der Prozesszeit t0 = time.clock() procedure() print time.clock() - t0, "Sekunden Prozesszeit" # messen der Echtzeit t0 = time.time() procedure() print time.time() - t0, "Sekunden Echtzeit" 0.0 Sekunden Prozesszeit 2.50903499126 Sekunden Echtzeit
Nicht alle Systeme kBnnen die wahre Prozeßzeit messen. Auf solchen Systemen (inkl. Windows) mißt clock normalerweise die seit Programmstart abgelaufene Echtzeit.
63
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Die Prozeßzeit hat eine begrenzte Genauigkeit. Auf vielen Systemen beginnt sie nach nur knapp 30 Minuten von vorne abzulaufen. Siehe auch das Modul timing, das die Echtzeit zwischen zwei Ereignissen mißt.
Das Modul types Das Modul types enth;lt Typobjekte fr alle in der Standardbibliothek definierten Objekttypen, wie in Beispiel 1-86 gezeigt. Alle Objekte desselben Typs teilen sich ein einzelnes Typobjekt. Sie kBnnen mit is testen, ob ein Objekt einen bestimmten Typ hat. Beispiel 1-86: Verwendung des Moduls types File: types-example-1.py import types def check(object): print object, if type(object) is types.IntType: print "GANZZAHL", if type(object) is types.FloatType: print "FLIESSKOMMA", if type(object) is types.StringType: print "STRING", if type(object) is types.ClassType: print "KLASSE", if type(object) is types.InstanceType: print "INSTANZ", print check(0) check(0.0) check("0") class A: pass class B: pass check(A) check(B) a = A() b = B() check(a) check(b)
64
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul gc Beispiel 1-86: Verwendung des Moduls types (Fortsetzung) 0 GANZZAHL 0.0 FLIESSKOMMA 0 STRING A KLASSE B KLASSE INSTANZ INSTANZ
Beachten Sie, daß alle Klassen denselben Typ haben, dies gilt auch fr Instanzen. Verwenden Sie die eingebauten Funktionen issubclass und isinstance, um zu testen, zu welcher Klassenhierarchie eine Klasse oder eine Instanz gehBrt. Das Modul types zerstBrt den aktuellen Ausnahmezustand, wenn es das erstemal importiert wird. Mit anderen Worten: Importieren Sie es (oder irgendein anderes Modul, das es importiert!) nicht innerhalb des Ausnahme-Handlers.
Das Modul gc (Optional, 2.0 und sp;ter) Das Modul gc bietet eine Schnittstelle zur eingebauten zyklischen Speicherentsorgung (Garbage Collector). Python verwendet die Referenzz;hlung, um zu bestimmen, wann Objekte entsorgt werden sollen. Sobald die letzte Referenz auf ein Objekt verschwindet, wird das Objekt zerstBrt. Ab der Version 2.0 bietet Python auch eine zyklische Speicherentsorgung, die in regelm;ßigen Intervallen abl;uft. Dieser Mechanismus sucht nach Datenstrukturen, die auf sich selbst zeigen, und versucht, die Zyklen zu durchbrechen. Beispiel 1-87 zeigt dies. Sie kBnnen die Funktion gc.collect verwenden, um eine vollst;ndige Entsorgung zu erzwingen. Diese Funktion gibt die Anzahl der Objekte zurck, die entsorgt wurden. Beispiel 1-87: Verwendung des Moduls gc zur zyklischen Speicherentsorgung File: gc-example-1.py import gc # erzeuge ein einfaches Objekt mit Verweisen auf sich selbst class Node: def __init__(self, name): self.name = name self.parent = None self.children = [] def addchild(self, node): node.parent = self self.children.append(node)
65
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 1: Kernmodule Beispiel 1-87: Verwendung des Moduls gc zur zyklischen Speicherentsorgung (Fortsetzung) def __repr__(self): return "" % (repr(self.name), id(self)) # erstelle eine selbstbezuegliche Struktur root = Node("monty") root.addchild(Node("eric")) root.addchild(Node("john")) root.addchild(Node("michael")) # entferne unseren einzigen Verweis del root print gc.collect(), "unerreichbare Objekte" print gc.collect(), "unerreichbare Objekte" 12 unerreichbare Objekte 0 unerreichbare Objekte
Wenn Sie sicher sind, daß Ihr Programm keine Datenstrukturen erzeugt, die auf sich selbst verweisen, kBnnen Sie mit der Funktion gc.disable die Entsorgung unterbinden. Nach dem Aufruf dieser Funktion funktioniert Python 2.0 genau wie 1.5.2 und frher.
66
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
2 Weitere Standardmodule »Now, imagine that your friend kept complaining that she did’nt want to visit you since she found it too hard to climb up the drain pipe, and you kept telling her to use the friggin’ stairs like everyone else...« – eff-bot, Juni 1998
1bersicht Dieses Kapitel beschreibt eine Reihe von Modulen, die in vielen Python-Programmen verwendet werden. Es ist sehr wohl mBglich, große Python-Programme zu schreiben, ohne sie zu benutzen, aber sie kBnnen einem eine Menge Zeit und Aufwand ersparen.
Dateien und StrAme Das Modul fileinput erleichtert das Schreiben verschiedener Arten von Textfiltern. Es enth;lt eine Hllklasse, die es ermBglicht, mit einer einfachen for-in-Anweisung ber den Inhalt einer oder mehrerer Textdateien zu iterieren. Das Modul StringIO (und die Variante cStringIO) implementiert ein speicherresidentes Dateiobjekt. Man kann StringIO-Objekte an vielen verschiedenen Stellen benutzen, an denen Python ein gewBhnliches Dateiobjekt erwartet.
Typ-H7llen UserDict, UserList und UserString stellen dnne Hllen um die entsprechenden ein-
gebauten Datentypen dar. Im Gegensatz zu den eingebauten Typen kBnnen von diesen Hllen aber auch Unterklassen gebildet werden. Das kann sehr ntzlich sein, wenn Sie eine Klasse brauchen, die fast genauso funktioniert wie ein eingebauter Typ, aber eine oder mehrere zus;tzliche Methoden hat.
67
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule
Zufallszahlen Das Modul random enth;lt eine Reihe verschiedener Zufallszahlengeneratoren. Das Modul whrandom funktioniert ;hnlich, ermBglicht es aber zus;tzlich, mehrere Generator-Objekte zu erzeugen.
Pr7fsummen und Verschl7sselungsalgorithmen Die Module md5 und sha werden zur Berechnung von kryptographisch starken Nachrichtensignaturen (auch »Prfsummen« genannt) verwendet. Das Modul crypt implementiert eine DES-;hnliche Einweg-Verschlsselung. Dieses Modul ist normalerweise nur auf Unix-Systemen verfgbar. Das Modul rotor gestattet eine einfache Zweiweg-Verschlsselung.
Das Modul fileinput Das Modul fileinput ermBglicht es Ihnen, den Inhalt von einer oder mehreren Textdateien zu iterieren, wie in Beispiel 2-1 gezeigt. Beispiel 2-1: Verwendung des Moduls fileinput zur Iteration 6ber eine Textdatei File: fileinput-example-1.py import fileinput import sys for line in fileinput.input("samples/sample.txt"): sys.stdout.write("-> ") sys.stdout.write(line) -> -> -> -> -> -> ->
We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language. -- Donald E. Knuth, December 1974
Mit dem Modul fileinput kann man auch Metainformationen ber die aktuelle Zeile erhalten. Dies beinhaltet isfirstline, filename und lineno, wie Beispiel 2-2 zeigt. Beispiel 2-2: Verwendung des Moduls fileinput zur Behandlung mehrerer Dateien File: fileinput-example-2.py import fileinput import glob import string, sys
68
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul shutil Beispiel 2-2: Verwendung des Moduls fileinput zur Behandlung mehrerer Dateien (Fortsetzung) for line in fileinput.input(glob.glob("samples/*.txt")): if fileinput.isfirstline(): # erste Zeile einer Datei? sys.stderr.write("-- lesen von %s --\n" % fileinput.filename()) sys.stdout.write(str(fileinput.lineno()) + " " + string.upper(line)) -- lesen von samples\sample.txt -1 WE WILL PERHAPS EVENTUALLY BE WRITING ONLY SMALL 2 MODULES WHICH ARE IDENTIFIED BY NAME AS THEY ARE 3 USED TO BUILD LARGER ONES, SO THAT DEVICES LIKE 4 INDENTATION, RATHER THAN DELIMITERS, MIGHT BECOME 5 FEASIBLE FOR EXPRESSING LOCAL STRUCTURE IN THE 6 SOURCE LANGUAGE. 7 -- DONALD E. KNUTH, DECEMBER 1974
Textdateien an Ort und Stelle zu bearbeiten ist ebenfalls einfach. Setzen Sie einfach beim Aufruf der Funktion input das Schlsselwortargument inplace auf 1, und das Modul kmmert sich um den Rest. Dieses Vorgehen wird in Beispiel 2-3 gezeigt. Beispiel 2-3: Verwendung des Moduls fileinput zur Umwandlung von CRLF in LF File: fileinput-example-3.py import fileinput, sys for line in fileinput.input(inplace=1): # wandle Windows/DOS-Textdateien in Unix-Dateien if line[-2:] == "\r\n": line = line[:-2] + "\n" sys.stdout.write(line)
Das Modul shutil Das Hilfsmodul shutil enth;lt einige Funktionen zum Kopieren von Dateien und Verzeichnissen. Die in Beispiel 2-4 verwendete Funktion copy kopiert eine Datei auf etwa die gleiche Weise wie der cp-Befehl in Unix. Beispiel 2-4: Verwendung des Moduls shutil zum Kopieren von Dateien File: shutil-example-1.py import shutil import os for file in os.listdir("."): if os.path.splitext(file)[1] == ".py": print file shutil.copy(file, os.path.join("backup", file))
69
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-4: Verwendung des Moduls shutil zum Kopieren von Dateien (Fortsetzung) aifc-example-1.py anydbm-example-1.py array-example-1.py ...
Die Funktion copytree kopiert einen vollst;ndigen Verzeichnisbaum (wie cp -r), und rmtree lBscht einen vollst;ndigen Baum (identisch mit rm -r). Diese Funktionen werden in Beispiel 2-5 dargestellt. Beispiel 2-5: Verwendung des Moduls shutil zum Kopieren und LGschen von VerzeichnisbBumen File: shutil-example-2.py import shutil import os SOURCE = "samples" BACKUP = "samples-bak" # lege ein Backup-Verzeichnis an shutil.copytree(SOURCE, BACKUP) print os.listdir(BACKUP) # loesche es shutil.rmtree(BACKUP) print os.listdir(BACKUP) ['sample.wav', 'sample.jpg', 'sample.au', 'sample.msg', 'sample.tgz', ... Traceback (most recent call last): File "shutil-example-2.py", line 17, in ? print os.listdir(BACKUP) os.error: No such file or directory
Das Modul tempfile Das Modul tempfile in Beispiel 2-6 ermBglicht es, schnell eindeutige Namen fr tempor;re Dateien zu finden. Beispiel 2-6: Verwendung des Moduls tempfile zur Erzeugung von Dateinamen f6r temporBre Dateien File: tempfile-example-1.py import tempfile import os
70
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul StringIO Beispiel 2-6: Verwendung des Moduls tempfile zur Erzeugung von Dateinamen f6r temporBre Dateien (Fortsetzung) tempfile = tempfile.mktemp() print "tempfile", "=>", tempfile file = open(tempfile, "w+b") file.write("*" * 1000) file.seek(0) print len(file.read()), "Bytes" file.close() try: # entferne die Datei, wenn fertig os.remove(tempfile) except OSError: pass tempfile => C:\TEMP\~160-1 1000 Bytes
Die Funktion TemporaryFile w;hlt einen passenden Namen und Bffnet die Datei, wie in Beispiel 2-7 gezeigt. Sie stellt auch sicher, daß die Datei gelBscht wird, sobald sie geschlossen wird. (Unter Unix kann man eine geBffnete Datei lBschen, so daß sie verschwindet, wenn sie geschlossen wird. Auf anderen Plattformen wird dies mit Hilfe einer speziellen Hllklasse erledigt.) Beispiel 2-7: Verwendung des Moduls tempfile zum Mffnen temporBrer Dateien File: tempfile-example-2.py import tempfile file = tempfile.TemporaryFile() for i in range(100): file.write("*" * 100) file.close() # loescht die Datei!
Das Modul StringIO Das in Beispiel 2-8 gezeigte Modul stringio implementiert ein speicherresidentes Dateiobjekt. Dieses Objekt kann als Ein- oder Ausgabe bei den meisten Funktionen verwendet werden, die ein Standarddateiobjekt erwarten.
71
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-8: Verwendung des Moduls StringIO zum Lesen einer statischen Datei File: stringio-example-1.py import StringIO MESSAGE = "Dieser Mann beraubt irgendwo ein Dorf um einen Informatiker." file = StringIO.StringIO(MESSAGE) print file.read() Dieser Mann beraubt irgendwo ein Dorf um einen Informatiker.
Die Klasse StringIO implementiert alle bei eingebauten Dateiobjekten verfgbaren Methoden fr speicherresidente Dateien sowie eine getvalue-Methode, die den Wert des enthaltenen Strings zurckgibt. Beispiel 2-9 demonstriert diese Methode. Beispiel 2-9: Verwendung des Moduls StringIO zum Schreiben in eine Datei im Speicher File: stringio-example-2.py import StringIO file = StringIO.StringIO() file.write("Dieser Mann ist kein gew^hnlicher Mann. ") file.write("Dies ist Herr F. G. Supermann.") print file.getvalue() Dieser Mann ist kein gewThnlicher Mann. Dies ist Herr F. G. Supermann.
StringIO kann man dazu verwenden, eine umgeleitete Ausgabe des Python-Interpreters festzuhalten, wie in Beispiel 2-10 gezeigt. Beispiel 2-10: Verwendung des Moduls StringIO zum Festhalten der Ausgabe File: stringio-example-3.py import StringIO import string, sys stdout = sys.stdout sys.stdout = file = StringIO.StringIO() print """ According to Gbaya folktales, trickery and guile are the best ways to defeat the python, king of snakes, which was hatched from a dragon at the world's start. -- National Geographic, May 1997 """
72
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul cStringIO Beispiel 2-10: Verwendung des Moduls StringIO zum Festhalten der Ausgabe (Fortsetzung) sys.stdout = stdout print string.upper(file.getvalue()) ACCORDING TO GBAYA FOLKTALES, TRICKERY AND GUILE ARE THE BEST WAYS TO DEFEAT THE PYTHON, KING OF SNAKES, WHICH WAS HATCHED FROM A DRAGON AT THE WORLD'S START. -- NATIONAL GEOGRAPHIC, MAY 1997
Das Modul cStringIO Das Modul cStringIO ist optional und enth;lt eine schnellere Implementierung des Moduls StringIO. Es funktioniert genauso wie StringIO, man kann davon jedoch keine Unterklassen bilden. Beispiel 2-11 zeigt, wie cStringIO verwendet wird. Beispiel 2-11: Verwendung des Moduls cStringIO File: cstringio-example-1.py import cStringIO MESSAGE = "Dieser Mann beraubt irgendwo ein Dorf um einen Informatiker." file = cStringIO.StringIO(MESSAGE) print file.read() Dieser Mann beraubt irgendwo ein Dorf um einen Informatiker.
Um Ihren Code so schnell wie mBglich zu machen, aber auch robust genug, um ihn auf ;lteren Python-Installationen laufen zu lassen, kBnnen Sie auf das Modul StringIO zurckgreifen, wenn cStringIO nicht verfgbar ist, wie es in Beispiel 2-12 gemacht wird. Beispiel 2-12: R6ckgriff auf das Modul StringIO File: cstringio-example-2.py try: import cStringIO StringIO = cStringIO except ImportError: import StringIO print StringIO <module 'StringIO' (built-in)>
73
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule
Das Modul mmap (Neu in 2.0) Das Modul mmap bietet eine Schnittstelle zu jenen Betriebssystemfunktionen, mit denen Dateien implementiert sind, die direkt im Hauptspeicher abgelegt sind (engl. memory mapped files), wie in Beispiel 2-13 gezeigt. Der abgebildete Bereich verh;lt sich wie ein Stringobjekt, aber die Daten werden direkt aus der Datei gelesen. Beispiel 2-13: Verwendung des Moduls mmap File: mmap-example-1.py import mmap import os filename = "samples/sample.txt" file = open(filename, "r+") size = os.path.getsize(filename) data = mmap.mmap(file.fileno(), size) # Grundlegendes print data print len(data), size # lies mit Teilbereichsbildung aus der Datei print repr(data[:10]), repr(data[:10]) # oder verwende die Standard-Dateischnittstelle print repr(data.read(10)), repr(data.read(10)) <mmap object at 008A2A10> 302 302 'We will pe' 'We will pe' 'We will pe' 'rhaps even'
Unter Windows muß die Datei sowohl zum Lesen als auch zum Schreiben geBffnet sein (r+ oder w+), sonst wird mmap fehlschlagen. Beispiel 2-14 zeigt, daß oftmals in den Speicher abgebildete Bereiche statt gewBhnlicher Strings benutzt werden kBnnen, auch bei regul;ren Ausdrcken und vielen Stringoperationen. Beispiel 2-14: Verwendung von Stringfunktionen und regulBren Ausdr6cken auf einem Speicherbereich File: mmap-example-2.py import mmap import os, string, re
74
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul UserDict Beispiel 2-14: Verwendung von Stringfunktionen und regulBren Ausdr6cken auf einem Speicherbereich (Fortsetzung) def mapfile(filename): file = open(filename, "r+") size = os.path.getsize(filename) return mmap.mmap(file.fileno(), size) data = mapfile("samples/sample.txt") # suche index = data.find("small") print index, repr(data[index-5:index+15]) # Regulaere Ausdruecke funktionieren auch! m = re.search("small", data) print m.start(), m.group() 43 'only small\015\012modules ' 43 small
Das Modul UserDict Das Modul UserDict enth;lt eine Dictionary-Klasse, von der Unterklassen abgeleitet werden kBnnen (tats;chlich ist sie eine Python-Hlle fr den eingebauten DictionaryTyp). Beispiel 2-15 zeigt eine erweiterte Dictionary-Klasse, die es ermBglicht, Dictionaries zu anderen Dictionaries »hinzuzufgen« und sie mit Hilfe der Schlsselwortargument-Syntax zu initialisieren. Beispiel 2-15: Verwendung des Moduls UserDict File: userdict-example-1.py import UserDict class FancyDict(UserDict.UserDict): def __init__(self, data = {}, **kw): UserDict.UserDict.__init__(self) self.update(data) self.update(kw) def __add__(self, other): dict = FancyDict(self.data) dict.update(b) return dict a = FancyDict(a = 1) b = FancyDict(b = 2)
75
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-15: Verwendung des Moduls UserDict (Fortsetzung) print a + b {'b': 2, 'a': 1}
Das Modul UserList Das Modul UserList enth;lt eine Listenklasse, von der Unterklassen abgeleitet werden kBnnen (eine einfache Python-Hlle um den eingebauten Listentyp). In Beispiel 2-16 funktionieren Instanzen von AutoList genau wie gewBhnliche Listen, außer daß sie es Ihnen ermBglichen, Elemente am Ende der Liste hinzuzufgen, indem ihnen zugewiesen wird. Beispiel 2-16: Verwendung des Moduls UserList File: userlist-example-1.py import UserList class AutoList(UserList.UserList): def __setitem__(self, i, item): if i == len(self.data): self.data.append(item) else: self.data[i] = item list = AutoList() for i in range(10): list[i] = i print list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Das Modul UserString (Neu in 2.0) Das Modul UserString enth;lt zwei Klassen, UserString und MutableString. Erstere ist eine Hlle fr den Standard-String-Typ, von dem man Unterklassen bilden kann, w;hrend letztere eine Variante ist, die es ermBglicht, den String an Ort und Stelle zu modifizieren. Man beachte, daß MutableString nicht besonders effizient ist. Die meisten Operationen sind unter Verwendung von Teilbereichsbildung und Verknpfung von Strings implementiert. Falls Ihnen an einer guten Performanz gelegen ist, sollten Sie lieber Listen von
76
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul traceback Stringfragmenten oder das Modul array verwenden. Beispiel 2-17 zeigt die Verwendung des Moduls UserString. Beispiel 2-17: Verwendung des Moduls UserString File: userstring-example-1.py import UserString class MyString(UserString.MutableString): def append(self, s): self.data = self.data + s def insert(self, index, s): self.data = self.data[index:] + s + self.data[index:] def remove(self, s): self.data = self.data.replace(s, "") file = open("samples/book.txt") text = file.read() file.close() book = MyString(text) for bird in ["gannet", "robin", "nuthatch"]: book.remove(bird) print book ... C: The one without the ! P: The one without the -!!! They've ALL got the !! It's a Standard British Bird, the , it's in all the books!!! ...
Das Modul traceback Das in Beispiel 2-18 gezeigte Modul traceback ermBglicht es Ihnen, Ausnahme-Tracebacks in Ihren Programmen auszugeben, wie es der Interpreter auch macht, wenn Sie eine Ausnahme nicht selbst abfangen. Beispiel 2-18: Verwendung des Moduls traceback zur Ausgabe eines Tracebacks File: traceback-example-1.py # Achtung! Beim Import des Moduls traceback kommt der # Ausnahmezustand durcheinander; daher den Import besser # hier erledigen und nicht im Ausnahme-Handler.
77
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-18: Verwendung des Moduls traceback zur Ausgabe eines Tracebacks (Fortsetzung) import traceback try: raise SyntaxError, "Beispiel" except: traceback.print_exc() Traceback (innermost last): File "traceback-example-1.py", line 7, in ? SyntaxError: Beispiel
Beispiel 2-19 verwendet das Modul StringIO, um den Traceback in einem String abzulegen. Beispiel 2-19: Verwendung des Moduls traceback zum Kopieren eines Tracebacks in einen String File: traceback-example-2.py import traceback import StringIO try: raise IOError, "Ein I/O-Fehler ist aufgetreten" except: fp = StringIO.StringIO() traceback.print_exc(file=fp) message = fp.getvalue() print "Fehler! Der Fehler lautet:", repr(message) Fehler! Der Fehler lautet: 'Traceback (innermost last):\012 File "traceback-example-2.py", line 5, in ?\012IOError: Ein I/O-Fehler ist aufgetreten'
Um den Traceback auf eine nicht-standardisierte Art auszugeben, verwenden Sie die Funktion extract_tb, die ein Traceback-Objekt in eine Liste von Stapeleintr;gen konvertiert, wie in Beispiel 2-20 gezeigt. Beispiel 2-20: Verwendung des Moduls traceback zum Decodieren eines Traceback-Objekts File: traceback-example-3.py import traceback import sys def function(): raise IOError, "Ein I/O-Fehler ist aufgetreten" try: function()
78
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul errno Beispiel 2-20: Verwendung des Moduls traceback zum Decodieren eines Traceback-Objekts (Fortsetzung) except: info = sys.exc_info() for file, lineno, function, text in traceback.extract_tb(info[2]): print file, "Zeile", lineno, "in", function print "=>", repr(text) print "** %s: %s" % info[:2] traceback-example-3.py Zeile 8 in ? => 'function()' traceback-example-3.py Zeile 5 in function => 'raise IOError, "Ein I/O-Fehler ist aufgetreten"' ** exceptions.IOError: Ein I/O-Fehler ist aufgetreten
Das Modul errno Das Modul errno definiert eine Reihe von symbolischen Fehlercodes, wie z.B. ENOENT (»Kein solcher Verzeichniseintrag«) und EPERM (»Erlaubnis verweigert«). Es bietet außerdem eine Dictionary-Abbildung von plattformabh;ngigen numerischen Fehlercodes auf symbolische Namen. Beispiel 2-21 zeigt, wie errno benutzt wird. In den meisten F;llen gibt die Ausnahme IOError ein Zweier-Tupel mit dem numerischen Fehlercode und einem erkl;renden String zurck. Wenn Sie zwischen verschiedenen Fehlercodes unterscheiden mssen, sollten Sie – wann immer mBglich – die symbolischen Namen w;hlen. Beispiel 2-21: Verwendung des Moduls errno File: errno-example-1.py import errno try: fp = open("Keine.solche.Datei") except IOError, (error, message): if error == errno.ENOENT: print "Keine solche Datei" elif error == errno.EPERM: print "Erlaubnis verweigert" else: print message Keine solche Datei
Beispiel 2-22 wirkt ein wenig konstruiert, aber es zeigt, wie man das errorcode-Dictionary verwendet, um einen numerischen Fehlercode auf den symbolischen Namen abzubilden.
79
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-22: Verwendung des errorcode-Dictionarys File: errno-example-2.py import errno try: fp = open("Keine.solche.Datei") except IOError, (error, message): print error, repr(message) print errno.errorcode[error] 2 'No such file or directory' ENOENT
Das Modul getopt Das in Beispiel 2-23 verwendete Modul getopt enth;lt Funktionen zum Auslesen von Kommandozeilenoptionen und -argumenten. Es versteht sowohl die Kurz- als auch die Langform von Optionsformaten. Das zweite Argument gibt die erlaubten Kurzoptionen an. Ein Doppelpunkt (:) nach einem Optionsnamen bedeutet, daß der Option ein zus;tzliches Argument folgen muß. Beispiel 2-23: Verwendung des Moduls getopt File: getopt-example-1.py import getopt import sys # simuliere Aufruf von Kommandozeile sys.argv = ["myscript.py", "-l", "-d", "directory", "filename"] # verarbeite Optionen opts, args = getopt.getopt(sys.argv[1:], "ld:") long = 0 directory = None for o, v in opts: if o == "-l": long = 1 elif o == "-d": directory = v print "Lang", "=", long print "Verzeichnis", "=", directory print "Argumente", "=", args
80
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul getpass Beispiel 2-23: Verwendung des Moduls getopt (Fortsetzung) Lang = 1 Verzeichnis = directory Argumente = ['filename']
Um mit getopt wie in Beispiel 2-24 nach langen Optionen zu suchen, bergeben Sie eine Liste von Optionsbeschreibungen als drittes Argument. Falls ein Optionsname mit einem Gleichheitszeichen endet (=), muß diese Option ein zus;tzliches Argument haben. Beispiel 2-24: Verwendung des Moduls getopt zur Verarbeitung langer Optionen File: getopt-example-2.py import getopt import sys # simuliere Aufruf von Kommandozeile sys.argv = ["myscript.py", "--echo", "--printer", "lp01", "message"] opts, args = getopt.getopt(sys.argv[1:], "ep:", ["echo", "printer="]) # verarbeite Optionen echo = 0 printer = None for o, v in opts: if o in ("-e", "--echo"): echo = 1 elif o in ("-p", "--printer"): printer = v print "Echo", "=", echo print "Drucker", "=", printer print "Argumente", "=", args Echo = 1 Drucker = lp01 Argumente = ['message']
Das Modul getpass Das Modul getpass ermBglicht die plattformunabh;ngige Eingabe eines Paßworts in ein Kommandozeilenprogramm, wie in Beispiel 2-25 gezeigt. getpass(prompt) gibt den Promptstring aus, schaltet das Tastaturecho aus und liest ein Paßwort. Falls das Prompt-Argument weggelassen wird, gibt es »Password: « aus. getuser() ermittelt den aktuellen Benutzernamen, wenn mBglich.
81
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-25: Verwendung des Moduls getpass File: getpass-example-1.py import getpass usr = getpass.getuser() pwd = getpass.getpass("Passwort eingeben fuer Benutzer %s: " % usr) print usr, pwd Passwort eingeben fuer Benutzer mulder: mulder trustno1
Das Modul glob Das Modul glob erzeugt Dateilisten, deren Namen mit bestimmten Mustern bereinstimmen, genau wie in einer Unix-Shell. Dateimuster sind vergleichbar mit regul;ren Ausdrcken, sind aber einfacher. Ein Stern (*) stimmt mit keinem oder mehreren Zeichen berein, und ein Fragezeichen (?) stimmt mit genau einem Zeichen berein. Sie kBnnen auch eckige Klammern verwenden, um Bereiche von Zeichen anzugeben, z.B. [0-9] fr eine einzelne Ziffer. Alle anderen Zeichen stimmen nur mit sich selbst berein. glob(pattern) gibt eine Liste aller Dateien zurck, die mit einem gegebenen Muster bereinstimmen. Das Modul glob wird in Beispiel 2-26 gezeigt.
Beispiel 2-26: Verwendung des Moduls glob File: glob-example-1.py import glob for file in glob.glob("samples/*.jpg"): print file samples/sample.jpg
Man beachte, daß glob vollst;ndige Pfadnamen zurckgibt, anders als die Funktion os.listdir. glob benutzt das Modul fnmatch, um den eigentlichen Mustervergleich durchzufhren.
82
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul fnmatch
Das Modul fnmatch Das Modul fnmatch vergleicht Dateinamen mit einem Muster, wie in Beispiel 2-27 gezeigt. Die Syntax des Musters ist die gleiche wie diejenige, die in Unix-Shells verwendet wird. Ein Stern (*) stimmt mit keinem oder mehreren Zeichen berein, ein Fragezeichen (?) mit genau einem Zeichen. Sie kBnnen auch eckige Klammern verwenden, um Bereiche von Zeichen anzugeben, z.B. [0-9] fr eine beliebige Ziffer. Alle anderen Zeichen stimmen nur mit sich selbst berein. Beispiel 2-27: Verwendung des Moduls fnmatch zum Vergleich von Dateinamen File: fnmatch-example-1.py import fnmatch import os for file in os.listdir("samples"): if fnmatch.fnmatch(file, "*.jpg"): print file sample.jpg
In Beispiel 2-28 wandelt die Funktion translate ein Dateinamensmuster in einen regul;ren Ausdruck. Beispiel 2-28: Verwendung des Moduls fnmatch zur Umwandlung eines Musters in einen regulBren Ausdruck File: fnmatch-example-2.py import fnmatch import os, re pattern = fnmatch.translate("*.jpg") for file in os.listdir("samples"): if re.match(pattern, file): print file print "(Muster war %s)" % pattern sample.jpg (Muster war .*\.jpg$)
Das Modul fnmatch wird von den Modulen glob und find verwendet.
83
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule
Das Modul random »Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin.« – John von Neumann, 1951
Das Modul random enth;lt eine Reihe von Zufallszahlengeneratoren. Auf den einfachen Zufallszahlengenerator (nach einem Algorithmus von Wichmann und Hill, 1982) kann man auf mehrere Arten zugreifen, wie Beispiel 2-29 zeigt. Beispiel 2-29: Verwendung des Moduls random zur Erzeugung von Zufallszahlen File: random-example-1.py import random for i in range(5): # zufaellige Fliesskommazahl: 0.0 <= Zahl < 1.0 print random.random(), # zufaellige Fliesskommazahl: 10 <= Zahl < 20 print random.uniform(10, 20), # zufaellige Ganzzahl: 100 <= Zahl <= 1000 print random.randint(100, 1000), # zufaellige Ganzzahl: gerade Zahlen in 100 <= Zahl < 1000 print random.randrange(100, 1000, 2) 0.946842713956 0.573613195398 0.363241598013 0.602115173978 0.526767588533
19.5910069381 709 172 16.2758417025 407 120 16.8079747714 916 580 18.386796935 531 774 18.0783794596 223 344
Man beachte, daß die Funktion randint auch die obere Schranke zurckgeben kann, w;hrend die anderen Funktionen immer Werte kleiner als die obere Schranke zurckgeben. Beispiel 2-30 zeigt, wie die Funktion choice ein zuf;lliges Element einer Sequenz aussucht. Sie kann auf Listen, Tupeln oder einer beliebigen anderen Sequenz verwendet werden (vorausgesetzt natrlich, man hat einen wahlfreien Zugriff darauf). Beispiel 2-30: Verwendung des Moduls random f6r zufBllige Elemente einer Sequenz File: random-example-2.py import random
84
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul random Beispiel 2-30: Verwendung des Moduls random f6r zufBllige Elemente einer Sequenz (Fortsetzung) # zufaelliges Element einer Liste for i in range(5): print random.choice([1, 2, 3, 5, 9]) 2 3 1 9 1
Ab 2.0 kann man die Funktion shuffle benutzen, um den Inhalt einer Liste zu mischen, d.h. man erzeugt an Ort und Stelle eine zuf;llige Permutation der Liste. Beispiel 2-31 zeigt auch, wie man diese Funktion in der Version 1.5.2 und davor implementiert. Beispiel 2-31: Verwendung des Moduls random zum Mischen eines Kartenstapels File: random-example-4.py import random try: # verfuegbar ab Python 2.0 shuffle = random.shuffle except AttributeError: def shuffle(x): for i in xrange(len(x)-1, 0, -1): # waehle ein Element in x[:i+1], mit dem x[i] # getauscht werden soll j = int(random.random() * (i+1)) x[i], x[j] = x[j], x[i] cards = range(52) shuffle(cards) myhand = cards[:5] print myhand [4, 8, 40, 12, 30]
Das Modul random enth;lt auch Zufallsgeneratoren mit Verteilungen verschieden von der Gleichverteilung. Beispiel 2-32 verwendet die Funktion gauss, um Zufallszahlen mit einer Gauss-Verteilung zu erzeugen.
85
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-32: Verwendung des Moduls random f6r Gaussche Zufallszahlen File: random-example-3.py import random histogram = [0] * 20 # berechnet ein Histogramm fuer Gauss-Rauschen, # mit Mittelwert=5, Standardabweichung=1 for i in range(1000): i = int(random.gauss(5, 1) * 2) histogram[i] = histogram[i] + 1 # gib Histogramm aus m = max(histogram) for v in histogram: print "*" * (v * 50 / m) **** ********** ************************* *********************************** ************************************************ ************************************************** ************************************* *************************** ************* *** *
Weitere Informationen ber nicht gleichverteilte Generatoren finden Sie in der PythonBibliotheksreferenz.
Die in der Standardbibliothek enthaltenen Zufallszahlengeneratoren erzeugen Pseudo-Zufallszahlen. Dies mag fr viele Zwecke ausreichend sein – inklusive Simulationen, numerische Analysen und Spiele – , aber definitiv nicht fr kryptographische Anwendungen.
Das Modul whrandom Das in Beispiel 2-33 gezeigte Modul whrandom enth;lt einen Generator fr PseudoZufallszahlen (auf der Basis eines Algorithmus von Wichmann und Hill, 1982). Sofern Sie nicht mehrere unabh;ngige Generatoren brauchen (z.B. in einer Anwendung mit mehreren Threads), ist es besser, statt dessen die Funktionen im Modul random zu benutzen.
86
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul md5 Beispiel 2-33: Verwendung des Moduls whrandom File: whrandom-example-1.py import whrandom # identisch mit random print whrandom.random() print whrandom.choice([1, 2, 3, 5, 9]) print whrandom.uniform(10, 20) print whrandom.randint(100, 1000) 0.113412062346 1 16.8778954689 799
Beispiel 2-34 zeigt, wie man mehrere Generatoren als Instanzen der Klasse whrandom erzeugt. Beispiel 2-34: Verwendung des Moduls whrandom zur Erzeugung mehrerer Zufallsgeneratoren File: whrandom-example-2.py import whrandom # initialisiere alle Generatoren mit dem gleichen Startwert rand1 = whrandom.whrandom(4,7,11) rand2 = whrandom.whrandom(4,7,11) rand3 = whrandom.whrandom(4,7,11) for i in range(5): print rand1.random(), rand2.random(), rand3.random() 0.123993532536 0.180951499518 0.291924111809 0.952048889363 0.969794283643
0.123993532536 0.180951499518 0.291924111809 0.952048889363 0.969794283643
0.123993532536 0.180951499518 0.291924111809 0.952048889363 0.969794283643
Das Modul md5 Mit dem Modul md5 kBnnen Signaturen von Nachrichten, d.h. Prfsummen (engl. message digests), berechnet werden. Der md5-Algorithmus berechnet eine starke 128-Bit-Prfsumme. Das bedeutet: Wenn zwei Strings verschieden sind, ist es sehr wahrscheinlich, daß ihre md5-Prfsummen ebenfalls verschieden sind. Mit anderen Worten: Es ist fast unmBglich, zu einer gegebenen md5-Prfsumme einen String zu bestimmen, der diese Prfsumme erzeugt. Beispiel 2-35 demonstriert das Modul md5.
87
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-35: Verwendung des Moduls md5 File: md5-example-1.py import md5 hash = md5.new() hash.update("spam, spam, and eggs") print repr(hash.digest()) 'L\005J\243\266\355\243u`\305r\203\267\020F\303'
Man beachte, daß die Prfsumme als Bin;rstring zurckgegeben wird. Wie in Beispiel 2-36 gezeigt, ist es jedoch sehr einfach, einen hexadezimalen oder base64-codierten String zu erhalten. Beispiel 2-36: Verwendung des Moduls md5 zur Bestimmung eines hexadezimalen oder Base64codierten md5-Wertes File: md5-example-2.py import md5 import string import base64 hash = md5.new() hash.update("spam, spam, and eggs") value = hash.digest() print hash.hexdigest() # in Python 1.5.2 und davor verwende man statt dessen: # print string.join(map(lambda v: "%02x" % ord(v), value), "") print base64.encodestring(value) 4c054aa3b6eda37560c57283b71046c3 TAVKo7bto3VgxXKDtxBGww==
Beispiel 2-37 zeigt unter anderem, wie die md5-Prfsumme bei einer Abfrage-AntwortAuthentifizierung (Challenge-Response-Authentifizierung) eingesetzt werden kann (man beachte jedoch die sp;tere Bemerkung ber Zufallszahlen). Beispiel 2-37: Verwendung des Moduls md5 f6r Abfrage-Antwort-Authentifizierung File: md5-example-3.py import md5 import string, random
88
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul md5 Beispiel 2-37: Verwendung des Moduls md5 f6r Abfrage-Antwort-Authentifizierung (Fortsetzung) def getchallenge(): # Erzeuge einen 16 Byte langen Zufallsstring. (Beachte, dass der # eingebaute Pseudo-Zufallszahlengenerator einen 24-Bits-Startwert # benutzt, d.h., das ist nicht so toll wie es vielleicht aussieht...) challenge = map(lambda i: chr(random.randint(0, 255)), range(16)) return string.join(challenge, "") def getresponse(password, challenge): # berechne kombinierte Pruefsumme fuer Passwort und Abfrage m = md5.new() m.update(password) m.update(challenge) return m.digest() # # Server/Client-Kommunikation # 1. Client verbindet. Server gibt Abfrage aus. print "client:", "connect" challenge = getchallenge() print "server:", repr(challenge) # 2. Client kombiniert Passwort und Abfrage und berechnet # die Antwort. client_response = getresponse("trustno1", challenge) print "client:", repr(client_response) # # # #
3. Server macht selbiges und vergleicht das Ergebnis mit der Antwort des Clients. Das Resultat ist eine sichere Anmeldung, in der das Passwort niemals ueber den Kommunikationskanal geschickt wird.
server_response = getresponse("trustno1", challenge) if server_response == client_response: print "server:", "login ok" client: server: client: server:
connect '\334\352\227Z#\272\273\212KG\330\265\032>\311o' "l'\305\240-x\245\237\035\225A\254\233\337\225\001" login ok
Beispiel 2-38 enth;lt eine Variante von md5, mit der man Nachrichten fr den Versand ber ein Bffentliches Netz signieren kann, so daß ihre Integrit;t vom Empf;nger nachprfbar ist.
89
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-38: Verwendung des Moduls md5 f6r DatenintegritBtspr6fungen File: md5-example-4.py import md5 import array class HMAC_MD5: # Nachrichten-Authentifizierung mit MD5 def __init__(self, key): if len(key) > 64: key = md5.new(key).digest() ipad = array.array("B", [0x36] * 64) opad = array.array("B", [0x5C] * 64) for i in range(len(key)): ipad[i] = ipad[i] ^ ord(key[i]) opad[i] = opad[i] ^ ord(key[i]) self.ipad = md5.md5(ipad.tostring()) self.opad = md5.md5(opad.tostring()) def digest(self, data): ipad = self.ipad.copy() opad = self.opad.copy() ipad.update(data) opad.update(ipad.digest()) return opad.digest() # # simuliere Server-Seite key = "dies sollte ein wohlgehuetetes Geheimnis sein" message = open("samples/sample.txt").read() signature = HMAC_MD5(key).digest(message) # (sende Nachricht und Signatur ueber ein oeffentliches Netz) # # simuliere Client-Seite key = "dies sollte ein wohlgehuetetes Geheimnis sein" client_signature = HMAC_MD5(key).digest(message) if client_signature == signature: print "dies ist die Original-Nachricht:" print print message else: print "jemand hat die Nachricht veraendert!!!"
90
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sha Mit der Methode copy macht man einen Snapshot vom internen Zustand des Objekts. Dadurch kBnnen partielle Prfsummen vorberechnet werden, z.B. bei einem aufgefllten Schlssel wie in Beispiel 2-38. Fr weitere Details zu diesem Algorithmus siehe HMAC-MD5:Keyed-MD5 for Message Authentication (http://www.research.ibm.com/security/draft-ietf-ipsec-hmac-md5-00.txt) von Krawczyk, u.a.
Vergessen Sie nicht, daß die eingebauten Generatoren von Pseudo-Zufallszahlen fr Verschlsselungszwecke nicht gut genug sind. Seien Sie vorsichtig!
Das Modul sha Das Modul sha bietet eine andere MBglichkeit zur Berechnung von Prfsummen, wie Beispiel 2-39 zeigt. Es ;hnelt dem Modul md5, erzeugt statt dessen aber Prfsummen mit einer L;nge von 160 Bits. Beispiel 2-39: Verwendung des Moduls sha File: sha-example-1.py import sha hash = sha.new() hash.update("Spam, Spam und Eier") print repr(hash.digest()) print hash.hexdigest() '\xc6ot\x15\xb3\xb2\x03\x12;\x1c\xe2\x13\xb0\xa7\xa6\xc3o?\xa1\x0c' c66f7415b3b203123b1ce213b0a7a6c36f3fa10c
Fr weitere Anwendungen von sha-Signaturen sehen Sie sich die Beispiele zum Modul md5 an.
Das Modul crypt (Optional) Das Modul crypt implementiert eine Einweg-DES-Verschlsselung. Auf Unix-Systemen wird dieser Verschlsselungsalgorithmus verwendet, um PaßwBrter zu speichern, und dieses Modul ist wirklich nur dann ntzlich, wenn man solche PaßwBrter erzeugen oder berprfen mBchte.
91
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-40 zeigt, wie man ein Paßwort verschlsselt, indem man crypt.crypt mit dem Paßwortstring aufruft sowie einem Argument namens salt, das aus zwei zuf;lligen Buchstaben bestehen sollte. Nun kBnnen Sie das eigentliche Paßwort wegwerfen und brauchen nur den verschlsselten String aufzubewahren. Beispiel 2-40: Verwendung des Moduls crypt File: crypt-example-1.py import crypt import random, string def getsalt(chars = string.letters + string.digits): # generiere zufaelligen Startwert aus 2 Zeichen return random.choice(chars) + random.choice(chars) print crypt.crypt("bananas", getsalt()) 'py8UGrijma1j6'
Um ein gegebenes Paßwort zu verifizieren, verschlsseln Sie es unter Verwendung der beiden ersten Zeichen des verschlsselten Strings als salt-Argument. Wenn das Ergebnis mit dem verschlsselten String bereinstimmt, ist das Paßwort gltig. Beispiel 2-41 verwendet das Modul pwd, um fr einen bestimmten Benutzer das verschlsselte Paßwort zu ermitteln. Beispiel 2-41: Verwendung des Moduls crypt zur Authentifizierung File: crypt-example-2.py import pwd, crypt def login(user, password): "Pruefe, ob sich user mit password anmelden koennte." try: pw1 = pwd.getpwnam(user)[1] pw2 = crypt.crypt(password, pw1[:2]) return pw1 == pw2 except KeyError: return 0 # kein solcher Benutzer user = raw_input("Benutzername:") password = raw_input("Passwort:") if login(user, password): print "Willkommen", user else: print "Anmeldung fehlgeschlagen"
92
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul rotor Weitere Arten, eine Authentifizierung zu implementieren, sind in der Beschreibung des Moduls md5 zu finden.
Das Modul rotor (Optional) Das Modul rotor implementiert einen einfachen Verschlsselungsalgorithmus (siehe Beispiel 2-42), der auf der im Zweiten Weltkrieg verwendeten Chiffriermaschine Enigma beruht. Beispiel 2-42: Verwendung des Moduls rotor File: rotor-example-1.py import rotor SECRET_KEY = "spam" MESSAGE = "der heilige Gral" r = rotor.newrotor(SECRET_KEY) encoded_message = r.encrypt(MESSAGE) decoded_message = r.decrypt(encoded_message) print "Original:", repr(MESSAGE) print "verschluesselte Nachricht:", repr(encoded_message) print "entschluesselte Nachricht:", repr(decoded_message) Original: 'der heilige Gral' verschluesselte Nachricht: '\245\015\031...33s\361b\372a' entschluesselte Nachricht: 'der heilige Gral'
Das Modul zlib (Optional) Das Modul zlib untersttzt die Komprimierung mit »zlib«. (Diese Methode ist auch unter dem Namen »deflate« bekannt.) Beispiel 2-43 zeigt, wie die Funktionen compress und decompress auf Stringargumenten arbeiten. Beispiel 2-43: Verwendung des Moduls zlib zur Komprimierung eines Strings File: zlib-example-1.py import zlib MESSAGE = "Leben des Brian" compressed_message = zlib.compress(MESSAGE)
93
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-43: Verwendung des Moduls zlib zur Komprimierung eines Strings (Fortsetzung) decompressed_message = zlib.decompress(compressed_message) print "Original:", repr(MESSAGE) print "komprimierte Nachricht:", repr(compressed_message) print "dekomprimierte Nachricht:", repr(decompressed_message) Original: 'Leben des Brian' komprimierte Nachricht: 'x\234\363IMJ\315SHI-Vp*\312L\314\003\000)\307\005O' dekomprimierte Nachricht: 'Leben des Brian'
Die Komprimierungsrate variiert je nach Dateiinhalt sehr stark, wie man in Beispiel 2-44 sehen kann. Beispiel 2-44: Verwendung des Moduls zlib zur Komprimierung einer Gruppe von Dateien File: zlib-example-2.py import zlib import glob for file in glob.glob("samples/*"): indata = open(file, "rb").read() outdata = zlib.compress(indata, zlib.Z_BEST_COMPRESSION) print file, len(indata), "=>", len(outdata), print "%d%%" % (len(outdata) * 100 / len(indata)) samples\sample.au 1676 => 1109 66% samples\sample.gz 42 => 51 121% samples\sample.htm 186 => 135 72% samples\sample.ini 246 => 190 77% samples\sample.jpg 4762 => 4632 97% samples\sample.msg 450 => 275 61% samples\sample.sgm 430 => 321 74% samples\sample.tar 10240 => 125 1% samples\sample.tgz 155 => 159 102% samples\sample.txt 302 => 220 72% samples\sample.wav 13260 => 10992 82%
Sie kBnnen auch direkt komprimieren oder dekomprimieren, was in Beispiel 2-45 gezeigt wird. Beispiel 2-45: Verwendung des Moduls zlib zur Dekomprimierung von StrGmen File: zlib-example-3.py import zlib encoder = zlib.compressobj()
94
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul zlib Beispiel 2-45: Verwendung des Moduls zlib zur Dekomprimierung von StrGmen (Fortsetzung) data data data data
= = = =
encoder.compress("Leben") data + encoder.compress(" des ") data + encoder.compress("Brian") data + encoder.flush()
print repr(data) print repr(zlib.decompress(data)) 'x\234\363IMJ\315SHI-Vp*\312L\314\003\000)\307\005O' 'Leben des Brian'
Beispiel 2-46 zeigt, wie man es sich beim Lesen einer komprimierten Datei noch ein wenig bequemer machen kann, indem ein Decoder mit einem datei;hnlichen Objekt umhllt wird. Beispiel 2-46: Emulation eines Dateiobjekts f6r komprimierte StrGme File: zlib-example-4.py import zlib import string, StringIO class ZipInputStream: def __init__(self, file): self.file = file self.__rewind() def __rewind(self): self.zip = zlib.decompressobj() self.pos = 0 # Position im komprimierten Strom self.offset = 0 # Position im dekomprimierten Strom self.data = "" def __fill(self, bytes): if self.zip: # lies so lange, bis wir genug Bytes im Puffer haben while not bytes or len(self.data) < bytes: self.file.seek(self.pos) data = self.file.read(16384) if not data: self.data = self.data + self.zip.flush() self.zip = None # keine weiteren Daten break self.pos = self.pos + len(data) self.data = self.data + self.zip.decompress(data) def seek(self, offset, whence=0): if whence == 0: position = offset
95
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-46: Emulation eines Dateiobjekts f6r komprimierte StrGme (Fortsetzung) elif whence == 1: position = self.offset + offset else: raise IOError, "Ungueltiges Argument" if position < self.offset: raise IOError, "Kann nicht rueckwaerts suchen" # springe nach vorn, in 16K-Bloecken while position > self.offset: if not self.read(min(position - self.offset, 16384)): break def tell(self): return self.offset def read(self, bytes = 0): self.__fill(bytes) if bytes: data = self.data[:bytes] self.data = self.data[bytes:] else: data = self.data self.data = "" self.offset = self.offset + len(data) return data def readline(self): # sicherstellen, dass wir eine ganze Zeile haben while self.zip and "\n" not in self.data: self.__fill(len(self.data) + 512) i = string.find(self.data, "\n") + 1 if i <= 0: return self.read() return self.read(i) def readlines(self): lines = [] while 1: s = self.readline() if not s: break lines.append(s) return lines # # ausprobieren data = open("samples/sample.txt").read() data = zlib.compress(data) file = ZipInputStream(StringIO.StringIO(data))
96
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul code Beispiel 2-46: Emulation eines Dateiobjekts f6r komprimierte StrGme (Fortsetzung) for line in file.readlines(): print line[:-1] We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language. -- Donald E. Knuth, December 1974
Das Modul code Das Modul code bietet eine Reihe von Funktionen, mit denen das Verhalten des Standard-Interpreters im interaktiven Modus emuliert werden kann. Die Funktion compile_command verh;lt sich wie die eingebaute Funktion compile, fhrt jedoch zus;tzliche Tests durch, um sicherzustellen, daß Sie eine vollst;ndige PythonAnweisung bergeben. In Beispiel 2-47 kompilieren wir ein Programm Zeile fr Zeile und fhren die resultierenden Codeobjekte aus, sobald die Kompilierung beendet ist. Das Programm: a = ( 1, 2, 3 ) print a
Man beachte, daß die Tupel-Zuweisung nicht korrekt kompiliert werden kann, bis wir die zweite Klammer erreicht haben. Beispiel 2-47: Verwendung des Moduls code zur Kompilierung von Anweisungen File: code-example-1.py import code import string # SCRIPT = [ "a = (", " 1,", " 2,", " 3 ", ")", "print a" ]
97
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 2: Weitere Standardmodule Beispiel 2-47: Verwendung des Moduls code zur Kompilierung von Anweisungen (Fortsetzung) script = "" for line in SCRIPT: script = script + line + "\n" co = code.compile_command(script, "<stdin>", "exec") if co: # Die Anweisung ist komplett. Ausfuehren! print "-"*40 print script, print "-"*40 exec co script = "" ---------------------------------------a = ( 1, 2, 3 ) ------------------------------------------------------------------------------print a ---------------------------------------(1, 2, 3)
Die Klasse InteractiveConsole implementiert eine interaktive Konsole, ;hnlich derjenigen, die man erh;lt, wenn man den Python-Interpreter im interaktiven Modus startet. Die Konsole kann entweder aktiv sein (sie ruft eine Funktion auf, um die n;chste Zeile zu erhalten) oder passiv (Sie rufen die Methode push auf, sobald Sie neue Daten haben). In der Voreinstellung wird die eingebaute Funktion raw_input benutzt. $berschreiben Sie die Methode mit dem gleichen Namen, wenn Sie lieber eine andere Eingabefunktion benutzen. Beispiel 2-48 zeigt, wie man mit dem Modul code den interaktiven Interpreter emuliert. Beispiel 2-48: Verwendung des Moduls code zur Emulation des interaktiven Interpreters File: code-example-2.py import code console = code.InteractiveConsole() console.interact() Python 1.5.2 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam (InteractiveConsole) >>> a = ( ... 1, ... 2,
98
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul code Beispiel 2-48: Verwendung des Moduls code zur Emulation des interaktiven Interpreters (Fortsetzung) ... 3 ... ) >>> print a (1, 2, 3)
Das Skript in Beispiel 2-49 definiert eine Funktion namens keyboard, die es Ihnen ermBglicht, an jeder Stelle in Ihrem Programm die Steuerung an den interaktiven Interpreter abzugeben. Beispiel 2-49: Verwendung des Moduls code zur einfachen Fehlersuche File: code-example-3.py def keyboard(banner=None): import code, sys # benutze Exception-Trick, um an aktuelles Frame zu kommen try: raise None except: frame = sys.exc_info()[2].tb_frame.f_back # werte Befehle im aktuellen Namensraum aus namespace = frame.f_globals.copy() namespace.update(frame.f_locals) code.interact(banner=banner, local=namespace) def func(): print "START" a = 10 keyboard() print "ENDE" func() START Python 1.5.2 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam (InteractiveConsole) >>> print a 10 >>> print keyboard ^Z ENDE
99
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
3 Threads und Prozesse »Well, since you last asked us to stop, this thread has moved from discussing languages suitable for professional programmers via accidental users to computer-phobic users. A few more iterations can make this thread really interesting...« – eff-bot, Juni 1996
1bersicht Dieses Kapitel beschreibt die Module, die Threads untersttzen und zum StandardPython-Interpreter gehBren. Beachten Sie, daß die Thread-Untersttzung optional und mBglicherweise in Ihrem Python-Interpreter nicht verfgbar ist. Dieses Kapitel beschreibt auch einige Module, die es ermBglichen, externe Prozesse unter Unix und Windows ablaufen zu lassen.
Threads Wenn Sie ein Python-Programm ablaufen lassen, beginnt die Ausfhrung oben im Hauptmodul und arbeitet sich nach unten durch. Schleifen dienen dazu, um Teile des Programms zu wiederholen, und Funktions- und Methodenaufrufe bertragen die Kontrolle auf einen anderen Bereich des Programms (jedoch nur vorbergehend). Mit Threads kann Ihr Programm mehrere Dinge zur gleichen Zeit tun. Jeder Thread hat seinen eigenen Kontrollfluß. W;hrend der eine Thread vielleicht gerade Daten aus einer Datei liest, kann ein anderer Thread den Bildschirm aktualisieren. Python benutzt einen globalen Interpreter-Lock, um zu verhindern, daß zwei Threads gleichzeitig auf dieselben internen Datenstrukturen zugreifen. Nur ein einziger Thread kann zu einer Zeit Python-Code ausfhren. Python schaltet automatisch nach kurzer Zeit zum n;chsten Thread um oder dann, wenn ein Thread l;ngerfristig besch;ftigt ist (z.B. wenn er Daten aus einer Datei liest oder wartet, bis das n;chste Byte ber eine Netzwerkverbindung eintrudelt).
101
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse Der globale Lock reicht aber nicht aus, um Probleme in Ihren eigenen Programmen auszuschließen. Wenn mehrere Threads gleichzeitig versuchen, das gleiche Datenobjekt zu bearbeiten, kann dies in einem inkonsistenten Zustand enden. Stellen Sie sich hierzu einen einfachen Cache vor: def getitem(key): item = cache.get(key) if item is None: # nicht im Cache; erzeuge einen neuen item = create_new_item(key) cache[key] = item return item
Wenn zwei Threads die Funktion getitem gleich nacheinander mit demselben fehlenden Schlssel aufrufen, ist es gut mBglich, daß sie create_new_item zweimal mit dem gleichen Argument aufrufen. W;hrend dies in vielen F;llen in Ordnung sein mag, kann es manchmal zu schwerwiegenden Problemen fhren. Um Probleme wie diese zu vermeiden, kBnnen Sie Lock-Objekte verwenden, um Threads zu synchronisieren. Ein Lock-Objekt kann jederzeit nur einem einzigen Thread gehBren, und somit kann man damit sicherstellen, daß nur ein einziger Thread den Code im FunktionskBrper von getitem ausfhren kann.
Prozesse Unter den meisten modernen Betriebssystemen l;uft jedes Programm in seinem eigenen Prozeß. Normalerweise starten Sie ein neues Programm oder einen Prozeß, indem Sie einen Befehl in die Shell eingeben oder einen Meneintrag ausw;hlen. Python ermBglicht darber hinaus, ein neues Programm aus einem Python-Programm heraus zu starten. Die meisten prozeßbezogenen Funktionen sind im Modul os definiert, siehe Abschnitt »Arbeiten mit Prozessen« in Kapitel 1.
Das Modul threading (Optional) Das Modul threading ist eine Schnittstelle auf hBherem Niveau zum Umgang mit Threads, wie in Beispiel 3-1 dargestellt. Es wurde angelehnt an die ThreadEinrichtungen von Java entworfen. Wie das primitivere Modul thread ist es nur verfgbar, wenn Ihr Interpreter mit Thread-Untersttzung erzeugt wurde. Um einen neuen Thread zu erzeugen, leitet man eine Unterklasse von der Klasse Thread ab und definiert die run-Methode. Zum Starten solcher Threads erzeugt man eine oder mehrere Instanzen von dieser Klasse und ruft die start-Methode auf. Die run-Methode jeder Instanz wird dann in ihrem eigenen Thread laufen.
102
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul threading Beispiel 3-1: Verwendung des Moduls threading File: threading-example-1.py import threading import time, random class Counter: def __init__(self): self.lock = threading.Lock() self.value = 0 def increment(self): self.lock.acquire() # kritischer Abschnitt self.value = value = self.value + 1 self.lock.release() return value counter = Counter() class Worker(threading.Thread): def run(self): for i in range(10): # etwas vortaeuschen, was 10-100 ms dauert value = counter.increment()# globalen Zaehler inkrementieren time.sleep(random.randint(10, 100) / 1000.0) print self.getName(), "-- Task", i, "fertig", value # # ausprobieren for i in range(10): Worker().start() # starte einen Worker Thread-1 Thread-3 Thread-7 Thread-1 Thread-4 fertig 5 Thread-8 fertig 6 ... Thread-6 Thread-4 Thread-9
------
Task Task Task Task Task
0 0 0 1 0
fertig 1 fertig 3 fertig 8 fertig 7 Thread-5 -- Task 0 fertig 4
-- Task 0 Thread-6 -- Task 0 fertig 9
-- Task 9 fertig 98 -- Task 9 fertig 99 -- Task 9 fertig 100
Beispiel 3-1 verwendet ebenfalls Lock-Objekte, um einen kritischen Bereich innerhalb des globalen Z;hlerobjekts zu erzeugen. Wenn Sie die Aufrufe von acquire und release weglassen, ist es ziemlich wahrscheinlich, daß der Z;hler die 100 nicht erreicht.
103
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse
Das Modul Queue Das Modul Queue stellt eine Thread-sichere Implementierung einer Warteschlange dar, dargestellt in Beispiel 3-2. Es bietet einen bequemen Weg, Python-Objekte zwischen verschiedenen Threads zu bewegen. Beispiel 3-2: Verwendung des Moduls Queue File: queue-example-1.py import threading import Queue import time, random WORKERS = 2 class Worker(threading.Thread): def __init__(self, queue): self.__queue = queue threading.Thread.__init__(self) def run(self): while 1: item = self.__queue.get() if item is None: break # Ende der Schlange erreicht # etwas vortaeuschen, was 10-100 ms dauert time.sleep(random.randint(10, 100) / 1000.0) print "Task", item, "fertig" # # ausprobieren queue = Queue.Queue(0) for i in range(WORKERS): Worker(queue).start() # starte einen Worker for i in range(10): queue.put(i) for i in range(WORKERS): queue.put(None) # markiere Schlangenenden Task Task Task Task Task
104
1 0 3 2 4
fertig fertig fertig fertig fertig
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul Queue Beispiel 3-2: Verwendung des Moduls Queue (Fortsetzung) Task Task Task Task Task
5 7 6 9 8
fertig fertig fertig fertig fertig
Beispiel 3-3 zeigt, wie Sie die L;nge der Warteschlange begrenzen kBnnen. Wenn die Produzenten-Threads die Warteschlange gefllt haben, blockieren sie so lange, bis Elemente aus der Schlange herausfliegen. Beispiel 3-3: Verwendung des Moduls Queue mit einer MaximalgrGße File: queue-example-2.py import threading import Queue import time, random WORKERS = 2 class Worker(threading.Thread): def __init__(self, queue): self.__queue = queue threading.Thread.__init__(self) def run(self): while 1: item = self.__queue.get() if item is None: break # Ende der Schlange erreicht # etwas vortaeuschen, was 10-100 ms dauert time.sleep(random.randint(10, 100) / 1000.0) print "Task", item, "fertig" # mit begrenzter Schlange ausfuehren queue = Queue.Queue(3) for i in range(WORKERS): Worker(queue).start() # starte einen Worker for item in range(10): print "push", item queue.put(item) for i in range(WORKERS): queue.put(None) # markiere Schlangenenden
105
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse Beispiel 3-3: Verwendung des Moduls Queue mit einer MaximalgrGße (Fortsetzung) push push push push push push Task push Task push Task push Task push Task Task Task Task Task Task
0 1 2 3 4 5 0 6 1 7 2 8 3 9 4 6 5 7 9 8
fertig fertig fertig fertig fertig fertig fertig fertig fertig fertig
Sie kBnnen das Verhalten beeinflussen, indem Sie Unterklassen bilden. Die Klasse in Beispiel 3-4 liefert eine einfache Priorit;tsschlange. Dabei nimmt sie an, daß alle hinzugefgten Elemente Tupel sind, wobei das erste Element die Priorit;t enth;lt (ein kleiner Wert bedeutet hBhere Priorit;t). Beispiel 3-4: Verwendung des Moduls Queue zur Implementierung einer PrioritBtsschlange File: queue-example-3.py import Queue import bisect Empty = Queue.Empty class PriorityQueue(Queue.Queue): "Thread-sichere Priorit_tsschlange" def _put(self, item): # sortiert einf`gen bisect.insort(self.queue, item) # # ausprobieren queue = PriorityQueue(0) # Elemente ungeordnet hinzuf`gen queue.put((20, "zweiter")) queue.put((10, "erster")) queue.put((30, "dritter"))
106
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul Queue Beispiel 3-4: Verwendung des Moduls Queue zur Implementierung einer PrioritBtsschlange (Fortsetzung) # Inhalt der Schlange ausgeben try: while 1: print queue.get_nowait() except Empty: pass dritter zweiter erster
Beispiel 3-5 zeigt eine einfache Stapel-Implementierung (last-in, first-out anstelle von first-in, first-out). Beispiel 3-5: Verwendung des Moduls Queue zur Implementierung eines Stapels File: queue-example-4.py import Queue Empty = Queue.Empty class Stack(Queue.Queue): "Thread-sicherer Stapel" def _put(self, item): # am Anfang der Schlange einf`gen, nicht am Ende self.queue.insert(0, item) # Aliase der Methoden push = Queue.Queue.put pop = Queue.Queue.get pop_nowait = Queue.Queue.get_nowait # # ausprobieren stack = Stack(0) # schiebe Elemente auf den Stapel stack.push("erster") stack.push("zweiter") stack.push("dritter") # Inhalt des Stapels ausgeben try: while 1: print stack.pop_nowait() except Empty: pass
107
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse Beispiel 3-5: Verwendung des Moduls Queue zur Implementierung eines Stapels (Fortsetzung) dritter zweiter erster
Das Modul thread (Optional) Das Modul thread stellt eine primitivere Schnittstelle fr die Thread-Verarbeitung zur Verfgung, wie man in Beispiel 3-6 sehen kann. Sie ist nur dann verfgbar, wenn Ihr Interpreter auch mit Thread-Untersttzung generiert wurde. Fr neuen Code sollten Sie lieber die hBher angesiedelte Schnittstelle im Modul threading benutzen. Beispiel 3-6: Verwendung des Moduls thread File: thread-example-1.py import thread import time, random def worker(): for i in range(50): # etwas vortaeuschen, was 10-100 ms dauert time.sleep(random.randint(10, 100) / 1000.0) print thread.get_ident(), "-- Task", i, "fertig" # # ausprobieren for i in range(2): thread.start_new_thread(worker, ()) time.sleep(1) print "Tschuess!" 311 -- Task 265 -- Task 265 -- Task 311 -- Task ... 265 -- Task 311 -- Task 265 -- Task Tschuess!
0 0 1 1
fertig fertig fertig fertig
17 fertig 13 fertig 18 fertig
Beachten Sie, daß bei Beendigung des Hauptprogramms alle Threads beendet werden. Das Modul threading kennt dieses Problem nicht.
108
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul commands
Das Modul commands (Nur Unix) Das Modul commands enth;lt ein paar ntzliche Funktionen, um externe Befehle unter Unix leichter ausfhren zu kBnnen. Beispiel 3-7 stellt dieses Modul vor. Beispiel 3-7: Verwendung des Moduls commands File: commands-example-1.py import commands stat, output = commands.getstatusoutput("ls -lR") print "Status ", "=>", stat print "Ausgabe", "=>", len(output), "Bytes" Status => 0 Ausgabe => 171046 Bytes
Das Modul pipes (Nur Unix) Das in Beispiel 3-8 gezeigte Modul pipes enth;lt untersttzende Funktionen, um »Konvertierungs-Pipelines« aufzubauen. Sie kBnnen aus einer Reihe von externen Werkzeugen eine Pipeline aufbauen und diese auf eine oder mehrere Dateien anwenden. Beispiel 3-8: Verwendung des Moduls pipes File: pipes-example-1.py import pipes t = pipes.Template() # erzeuge eine Pipeline t.append("sort", "--") t.append("uniq", "--") # etwas Text herausfiltern t.copy("samples/sample.txt", "") Alan Jones (ganz in Ordnung) Kevin Phillips-Bong (etwas dWmlich) Tarquin Fin-tim-lin-bin-whin-bim-lin-bus-stop-F'tang-F'tang-Olffi`Biscuitbarrel
109
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse
Das Modul popen2 Das Modul popen2 ermBglicht es Ihnen, einen externen Befehl ablaufen zu lassen, wobei Sie auf stdin und stdout (und mBglicherweise stderr) als individuelle StrBme zugreifen kBnnen. In Python 1.5.2 und frher wurde dieses Modul nur unter Unix untersttzt. In 2.0 sind die Funktionen auch unter Windows implementiert. Beispiel 3-9 zeigt, wie man mit diesem Modul Strings sortieren kann. Beispiel 3-9: Verwendung des Moduls popen2 zum Sortieren von Strings File: popen2-example-1.py import popen2, string fin, fout = popen2.popen2("sort") fout.write("foo\n") fout.write("bar\n") fout.close() print fin.readline(), print fin.readline(), fin.close() bar foo
Beispiel 3-10 zeigt, wie Sie mit Hilfe dieses Moduls eine existierende Anwendung steuern kBnnen. Beispiel 3-10: Verwendung des Moduls popen2 zur Steuerung von gnuchess File: popen2-example-2.py import popen2 import string class Chess: "Interface-Klasse f`r chesstool-kompatible Programme" def __init__(self, engine = "gnuchessc"): self.fin, self.fout = popen2.popen2(engine) s = self.fin.readline() if s != "Chess\n": raise IOError, "inkompatibles Schachprogramm" def move(self, move): self.fout.write(move + "\n") self.fout.flush()
110
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul signal Beispiel 3-10: Verwendung des Moduls popen2 zur Steuerung von gnuchess (Fortsetzung) my = self.fin.readline() if my == "Illegal move": raise ValueError, "ung`ltiger Zug" his = self.fin.readline() return string.split(his)[2] def quit(self): self.fout.write("quit\n") self.fout.flush() # # spiele ein paar Zuege g = Chess() print g.move("a2a4") print g.move("b2b3") g.quit() b8c6 e7e5
Das Modul signal Das Modul signal wird benutzt, um eigene Signal-Handler zu installieren, siehe dazu Beispiel 3-11. Wenn der Interpreter ein Signal erkennt, wird die entsprechende Signalbehandlung so bald wie mBglich ausgelBst. Beispiel 3-11: Verwendung des Moduls signal File: signal-example-1.py import signal import time def handler(signo, frame): print "Signal", signo, "empfangen" signal.signal(signal.SIGALRM, handler) # wecke mich in 2 Sekunden signal.alarm(2) now = time.time() time.sleep(200)
111
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 3: Threads und Prozesse Beispiel 3-11: Verwendung des Moduls signal (Fortsetzung) print "habe", time.time() - now, "Sekunden geschlafen" Signal 14 empfangen habe 1.99262607098 Sekunden geschlafen
112
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
4 Datenrepr#sentation »PALO ALTO, Calif. – Intel says its Pentium Pro and new Pentium II chips have a flaw that can cause computers to sometimes make mistakes but said the problems could be fixed easily with rewritten software.« – Reuters Telegramm
1bersicht Dieses Kapitel beschreibt eine Reihe von Modulen, die zur Umwandlung zwischen Python-Objekten und anderen Datenrepr;sentationen verwendet werden kBnnen. Diese Module werden oft dazu verwendet, andere Dateiformate zu lesen und zu schreiben und um Python-Variablen zu speichern bzw. zu bertragen.
Bin#rdaten Python bietet verschiedene Hilfsmodule, mit denen bin;re Datenformate leichter codiert und decodiert werden kBnnen. Das Modul struct kann zwischen bin;ren Datenstrukturen (wie C-structs) und Python-Tupeln konvertieren. Das Modul array verpackt bin;re Daten-Arrays (Arrays in C) in ein Sequenzobjekt in Python.
Selbstbeschreibende Formate Um Daten zwischen verschiedenen Python-Programmen auszutauschen, kBnnen Sie diese mit marshal oder pickle behandeln. Das Modul marshal benutzt ein einfaches selbstbeschreibendes Format, das die meisten eingebauten Datentypen inklusive Codeobjekte untersttzt. Python selbst benutzt dieses Format, um kompilierten Code auf der Festplatte zu speichern, n;mlich in den PYCDateien.
113
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Das Modul pickle bietet ein ausgeklgelteres Format, das benutzerdefinierte Klassen, selbstreferenzierende Datenstrukturen und mehr untersttzt. Dieses Modul ist in zwei Versionen verfgbar. Die einfache Version von pickle ist in Python geschrieben und relativ langsam, w;hrend cPickle in C geschrieben und normalerweise genauso schnell ist wie marshal.
Ausgabeformatierung Die Module in dieser Gruppe erg;nzen eingebaute Funktionen fr die Ausgabeformatierung, wie z.B. repr und den String-Formatierungsoperator %. Das Modul pprint kann fast jede Datenstruktur in Python in einer hbschen, lesbaren Form ausgeben (so lesbar, wie es ihm nur irgend mBglich ist). Das Modul repr stellt einen Ersatz fr die eingebaute Funktion gleichen Namens dar. Die Version in diesem Modul nimmt jedoch einige strenge Einschr;nkungen bei den meisten Dingen vor: Sie gibt nicht mehr als 30 Zeichen eines Strings aus, sie gibt nur ein paar Ebenen einer tief verschachtelten Datenstruktur aus usw.
Codierte Bin#rdaten Python untersttzt die meisten Bin;rcodierungen wie z.B. base64, binhex (ein Macintosh-Format), quoted printable und die uu-Codierung.
Das Modul array Das Modul array implementiert einen effizienten Datentyp zur Speicherung von Arrays. Arrays sind vergleichbar mit Listen, aber alle Elemente mssen vom gleichen Grunddatentyp sein. Der Datentyp wird bei der Erzeugung des Arrays definiert. Die Beispiele 4-1 bis 4-5 sind sehr einfach gehalten. Beispiel 4-1 erzeugt ein arrayObjekt und kopiert den internen Puffer mit der Methode tostring in einen String. Beispiel 4-1: Verwendung des Moduls array zur Umwandlung von Listen von Ganzzahlen in Strings File: array-example-1.py import array a = array.array("B", range(16)) # unsigned char b = array.array("h", range(16)) # signed short print a print repr(a.tostring()) print b print repr(b.tostring())
114
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul array Beispiel 4-1: Verwendung des Moduls array zur Umwandlung von Listen von Ganzzahlen in Strings (Fortsetzung) array('B', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) '\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017' array('h', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) '\000\000\001\000\002\000\003\000\004\000\005\000\006\000\007\000 \010\000\011\000\012\000\013\000\014\000\015\000\016\000\017\000'
array-Objekte kBnnen bis zu einem gewissen Grad als normale Listen behandelt werden, wie Beispiel 4-2 zeigt. Sie kBnnen Arrays allerdings nicht verketten, wenn sie verschiedene Typ-Codes haben. Beispiel 4-2: Verwendung von Arrays als gewGhnliche Sequenzen File: array-example-2.py import array a = array.array("B", [1, 2, 3]) a.append(4) a = a + a a = a[2:-2] print a print repr(a.tostring()) for i in a: print i, array('B', [3, 4, 1, 2]) '\003\004\001\002' 3 4 1 2
Dieses Modul ermBglicht auch auf sehr effiziente Art, rohe Bin;rdaten in eine Sequenz von Ganzzahlen umzuwandeln (oder auch Fließkommawerte), wie Beispiel 4-3 zeigt. Beispiel 4-3: Verwendung von Arrays zur Umwandlung von Strings in Listen von Ganzzahlen File: array-example-3.py import array a = array.array("i", "Fischerei-Schein") # signed integer print a print repr(a.tostring()) print a.tolist()
115
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-3: Verwendung von Arrays zur Umwandlung von Strings in Listen von Ganzzahlen (Fortsetzung) array('i', [1668507974, 1701995880, 1666395497, 1852401000]) 'Fischerei-Schein' [1668507974, 1701995880, 1666395497, 1852401000]
Und schließlich zeigt Beispiel 4-4 , wie man mit diesem Modul die Byte-Reihenfolge (engl. endianess) der aktuellen Plattform bestimmen kann. Beispiel 4-4: Verwendung des Moduls array zur Bestimmung der plattformspezifischen ByteReihenfolge File: array-example-4.py import array def little_endian(): return ord(array.array("i",[1]).tostring()[0]) if little_endian(): print "Little-Endian-Plattform (Intel, Alpha)" else: print "Big-Endian-Plattform (Motorola, Sparc)" Big-Endian-Plattform (Motorola, Sparc)
In Python 2.0 und sp;ter existiert das Attribut sys.byteorder, das entweder auf little oder big gesetzt ist, wie Sie in Beispiel 4-5 sehen kBnnen. Beispiel 4-5: Verwendung des Attributs sys.byteorder zur Bestimmung der plattformspezifischen Byte-Reihenfolge (Python 2.0) File: sys-byteorder-example-1.py import sys # verfuegbar ab Python 2.0 if sys.byteorder == "little": print "Plattform ist Little-Endian (Intel, Alpha)" else: print "Plattform ist Big-Endian (Motorola, Sparc)" Plattform ist Big-Endian (Motorola, Sparc)
116
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul struct
Das Modul struct Das in Beispiel 4-6 gezeigte Modul struct enth;lt Funktionen zur Konvertierung zwischen Bin;rstrings und Python-Tupeln. Die Funktion pack erwartet einen Formatstring und ein oder mehrere Argumente und gibt einen Bin;rstring zurck. Die Funktion unpack erwartet einen String und gibt ein Tupel zurck. Beispiel 4-6: Verwendung des Moduls struct File: struct-example-1.py import struct # native Byte-Ordnung buffer = struct.pack("ihb", 1, 2, 3) print repr(buffer) print struct.unpack("ihb", buffer) # Daten aus einer Sequenz, Netzwerk-Byte-Ordnung data = [1, 2, 3] buffer = struct.pack("!ihb", *data) # in Python 1.5.2 und davor verwende man statt dessen: # buffer = apply(struct.pack, ("!ihb",) + tuple(data)) print repr(buffer) print struct.unpack("!ihb", buffer) '\001\000\000\000\002\000\003' (1, 2, 3) '\000\000\000\001\000\002\003' (1, 2, 3)
Das Modul xdrlib Das Modul xdrlib konvertiert zwischen Datentypen in Python und dem von der Firma Sun entwickelten Format XDR (eXternal Data Representation), wie in Beispiel 4-7 gezeigt. Beispiel 4-7: Verwendung des Moduls xdrlib File: xdrlib-example-1.py import xdrlib # # erzeuge einen Packer und uebergib ihm einige Daten p = xdrlib.Packer() p.pack_uint(1)
117
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-7: Verwendung des Moduls xdrlib (Fortsetzung) p.pack_string("spam") data = p.get_buffer() print "eingepackt:", repr(data) # # erzeuge einen Unpacker und decodiere damit die Daten u = xdrlib.Unpacker(data) print "ausgepackt:", u.unpack_uint(), repr(u.unpack_string()) u.done() eingepackt: '\000\000\000\001\000\000\000\004spam' ausgepackt: 1 'spam'
Das XDR-Format wird von Suns RPC-Protokoll (Remote Procedure Call) verwendet. Beispiel 4-8 ist ein unvollst;ndiges (und ziemlich konstruiertes) Beispiel, das zeigt, wie man ein Paket baut, das eine RPC-Anfrage darstellt. Beispiel 4-8: Verwendung des Moduls xdrlib zum Senden eines RPC-Aufrufpakets File: xdrlib-example-2.py import xdrlib # einige Konstanten (siehe RPC-Spezifikation fuer Details) RPC_CALL = 1 RPC_VERSION = 2 MY_PROGRAM_ID = 1234 # zugewiesen von Sun MY_VERSION_ID = 1000 MY_TIME_PROCEDURE_ID = 9999 AUTH_NULL = 0 transaction = 1 p = xdrlib.Packer() # sende ein Sun-RPC-Aufrufpaket p.pack_uint(transaction) p.pack_enum(RPC_CALL) p.pack_uint(RPC_VERSION) p.pack_uint(MY_PROGRAM_ID) p.pack_uint(MY_VERSION_ID) p.pack_uint(MY_TIME_PROCEDURE_ID) p.pack_enum(AUTH_NULL) p.pack_uint(0)
118
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul marshal Beispiel 4-8: Verwendung des Moduls xdrlib zum Senden eines RPC-Aufrufpakets (Fortsetzung) p.pack_enum(AUTH_NULL) p.pack_uint(0) print repr(p.get_buffer()) '\000\000\000\001\000\000\000\001\000\000\000\002\000\000\004\322 \000\000\003\350\000\000\'\017\000\000\000\000\000\000\000\000\000 \000\000\000\000\000\000\000'
Das Modul marshal Das Modul marshal wird benutzt, um Daten zu serialisieren, d.h. um Daten in und aus Zeichenketten zu konvertieren, so daß sie in Dateien gespeichert oder ber ein Netzwerk versendet werden kBnnen. Dies wird in Beispiel 4-9 gezeigt. Das Modul marshal verwendet ein einfaches selbstbeschreibendes Datenformat. Fr jedes Datum enth;lt der von marshal gewonnene String einen Typ-Code, gefolgt von einem oder mehreren typspezifischen Feldern. Ganzzahlen werden in der Byte-Reihenfolge Little-Endian gespeichert, Strings werden als L;ngenfeld gespeichert, gefolgt vom Stringinhalt (der auch Null-Bytes enthalten darf), Tupel als L;ngenfeld, gefolgt von den Objekten, aus denen sich das Tupel zusammensetzt usw. Beispiel 4-9: Verwendung des Moduls marshal zur Datenserialisierung File: marshal-example-1.py import marshal value = ( "dies ist ein String", [1, 2, 3, 4], ("mehr Tupel", 1.0, 2.3, 4.5), "dies ist ein weiterer String" ) data = marshal.dumps(value) # Zwischenformat print type(data), len(data) print "-"*58 print repr(data) print "-"*58 print marshal.loads(data)
119
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-9: Verwendung des Moduls marshal zur Datenserialisierung (Fortsetzung) 116 ---------------------------------------------------------'(\004\000\000\000s\023\000\000\000dies ist ein String [\004\000\000\000i\001\000\000\000i\002\000\000\000i\003 \000\000\000i\004\000\000\000(\004\000\000\000s\015\000 \000\000mehr Tupelf\0031.0f\0032.3f\0034.5s\023\000\000 \000dies ist ein weiterer String' ---------------------------------------------------------('dies ist ein String', [1, 2, 3, 4], ('mehr Tupel', 1.0, 2.2999999999999998, 4.5), 'dies ist ein weiterer String')
Das Modul marshal kann auch mit Codeobjekten umgehen (es wird verwendet, um vorkompilierte Python-Module zu speichern). Dies wird in Beispiel 4-10 gezeigt. Beispiel 4-10: Verwendung des Moduls marshal zur Codeserialisierung File: marshal-example-2.py import marshal script = """ print 'Hallo' """ code = compile(script, "<script>", "exec") data = marshal.dumps(code) # Zwischenformat print type(data), len(data) print "-"*50 print repr(data) print "-"*50 exec marshal.loads(data) 81 -------------------------------------------------'c\000\000\000\000\001\000\000\000s\017\000\000\000 \177\000\000\177\002\000d\000\000GHd\001\000S(\002 \000\000\000s\005\000\000\000HalloN(\000\000\000 \000(\000\000\000\000s\010\000\000\000<script>s\001 \000\000\000?\002\000s\000\000\000\000' -------------------------------------------------Hallo
120
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul pickle
Das Modul pickle Das in Beispiel 4-11 gezeigte Modul pickle wird zur Serialisierung von Daten benutzt, d.h. um Daten aus in Zeichenketten zu konvertieren, so daß sie in einer Datei gespeichert oder ber ein Netzwerk versendet werden kBnnen. Es ist etwas langsamer als marshal, kann jedoch unter anderem auch mit Klasseninstanzen, gemeinsam benutzten Elementen und rekursiven Datenstrukturen umgehen. Beispiel 4-11: Verwendung des Moduls pickle File: pickle-example-1.py import pickle value = ( "dies ist ein String", [1, 2, 3, 4], ("mehr Tupel", 1.0, 2.3, 4.5), "dies ist ein weiterer String" ) data = pickle.dumps(value) # Zwischenformat print type(data), len(data) print "-"*60 print data print "-"*60 print pickle.loads(data) 140 ----------------------------------------------------------(S'dies ist ein String' p0 (lp1 I1 aI2 aI3 aI4 a(S'mehr Tupel' p2 F1.0 F2.2999999999999998 F4.5 tp3 S'dies ist ein weiterer String' p4 tp5 .
121
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-11: Verwendung des Moduls pickle (Fortsetzung) ----------------------------------------------------------('dies ist ein String', [1, 2, 3, 4], ('mehr Tupel', 1.0, 2.2999999999999998, 4.5), 'dies ist ein weiterer String')
Andererseits beherrscht pickle keine Codeobjekte verarbeiten (das Modul copy_reg bietet jedoch eine MBglichkeit dies zu beheben). Per Voreinstellung benutzt pickle ein textbasiertes Format. Man kann auch ein Bin;rformat verwenden, in dem Zahlen und Bin;rstrings in einem kompakten Bin;rformat gespeichert werden. Das Bin;rformat fhrt normalerweise zu kleineren Dateien. Dies wird in Beispiel 4-12 gezeigt. Beispiel 4-12: Verwendung des Moduls pickle im BinBrmodus File: pickle-example-2.py import pickle import math value = ( "dies ist ein langer String" * 100, [1.2345678, 2.3456789, 3.4567890] * 100 ) # Textmodus data = pickle.dumps(value) print type(data), len(data), pickle.loads(data) == value # Binaermodus data = pickle.dumps(value, 1) print type(data), len(data), pickle.loads(data) == value
Das Modul cPickle (Optional) Das in Beispiel 4-13 gezeigte Modul cPickle enth;lt eine schnellere Reimplementierung des Moduls pickle. Beispiel 4-13: Verwendung des Moduls cPickle File: cpickle-example-1.py try: import cPickle pickle = cPickle except ImportError: import pickle
122
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul copy_reg Beispiel 4-13: Verwendung des Moduls cPickle (Fortsetzung) class Sample: def __init__(self, value): self.value = value sample = Sample(1) data = pickle.dumps(sample) print pickle print repr(data) <module 'cPickle' (built-in)> "(i__main__\012Sample\012p1\012(dp2\012S'value'\012p3\012I1\012sb."
Das Modul copy_reg Das Modul copy_reg bietet eine Registrierung, mit der Sie Ihre eigenen Erweiterungstypen registrieren kBnnen. Die Module pickle und copy benutzen diese Registrierung, um herauszufinden, wie Nicht-Standardtypen zu behandeln sind. Die Standard-Implementierung von pickle beherrscht z.B. keine Python-Codeobjekte, wie in folgendem Beispiel gezeigt wird: File: copy-reg-example-1.py import pickle CODE = """ print 'Guten Abend' """ code = compile(CODE, "<string>", "exec") exec code exec pickle.loads(pickle.dumps(code)) Guten Abend Traceback (innermost last): ... pickle.PicklingError: can't pickle 'code' objects
Dem kBnnen wir dadurch abhelfen, daß wir einen speziellen Handler fr Codeobjekte registrieren. Solch ein Handler besteht aus zwei Teilen: einem Pickler, der aus einem Codeobjekt ein Tupel macht, das nur einfache Datentypen enthalten kann, und einem Unpickler, der die Inhalte eines solchen Tupels als Argumente erwartet. Siehe Beispiel 4-14.
123
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-14: Verwendung des Moduls copy_reg, um die Serialisierung von Codeobjekten zu ermGglichen File: copy-reg-example-2.py import copy_reg import pickle, marshal, types # # registriere einen pickle-Handler fuer Codeobjekte def code_unpickler(data): return marshal.loads(data) def code_pickler(code): return code_unpickler, (marshal.dumps(code),) copy_reg.pickle(types.CodeType, code_pickler, code_unpickler) # # probiere es aus CODE = """ print "angenommen, er hat einen spitzen Stock" """ code = compile(CODE, "<string>", "exec") exec code exec pickle.loads(pickle.dumps(code)) angenommen, er hat einen spitzen Stock angenommen, er hat einen spitzen Stock
Wenn Sie die serialisierten Daten ber ein Netzwerk oder an ein anderes Programm schicken, muß der spezifische unpickler auf der Empf;ngerseite ebenfalls verfgbar sein. Den wahrhaft Abenteuerlustigen zeigt Beispiel 4-15 eine Version, mit der man geBffnete Dateiobjekte serialisieren kann. Beispiel 4-15: Verwendung des Moduls copy_reg, um die Serialisierung von Dateiobjekten zu ermGglichen File: copy-reg-example-3.py import copy_reg import pickle, types import StringIO # # registriere einen pickle-Handler fuer Dateiobjekte
124
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul pprint Beispiel 4-15: Verwendung des Moduls copy_reg, um die Serialisierung von Dateiobjekten zu ermGglichen (Fortsetzung) def file_unpickler(position, data): file = StringIO.StringIO(data) file.seek(position) return file def file_pickler(code): position = file.tell() file.seek(0) data = file.read() file.seek(position) return file_unpickler, (position, data) copy_reg.pickle(types.FileType, file_pickler, file_unpickler) # # probiere es aus file = open("samples/sample.txt", "rb") print file.read(120), print "", print pickle.loads(pickle.dumps(file)).read() We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language. -- Donald E. Knuth, December 1974
Das Modul pprint Das in Beispiel 4-16 gezeigte Modul pprint ist ein »Pretty-Printer« fr Python-Datenstrukturen. Es ist dann ntzlich, wenn man nicht-triviale Datenstrukturen auf der Konsole ausgeben muß. Beispiel 4-16: Verwendung des Moduls pprint File: pprint-example-1.py import pprint data = ( "dies ist ein String", [1, 2, 3, 4], ("mehr Tupel", 1.0, 2.3, 4.5), "dies ist ein weiterer String" )
125
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-16: Verwendung des Moduls pprint (Fortsetzung) pprint.pprint(data) ('dies ist ein String', [1, 2, 3, 4], ('mehr Tupel', 1.0, 2.2999999999999998, 4.5), 'dies ist ein weiterer String')
Das Modul repr Das Modul repr bietet eine Version der eingebauten Funktion repr mit Einschr;nkungen auf den meisten GrBßen (Stringl;ngen, Rekursion usw.). Beispiel 4-17 zeigt, wie man das Modul verwendet. Beispiel 4-17: Verwendung des Moduls repr File: repr-example-1.py # beachte: dies ueberschreibt die eingebaute Funktion 'repr' from repr import repr # eine stoerende rekursive Datenstruktur data = ( "X" * 100000, ) data = [data] data.append(data) print repr(data) [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [('XXXXXXXXXXXX...XXXXXXXXXX XXX',), [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [('XXXXXXXXXXXX...XX XXXXXXXXXXX',), [('XXXXXXXXXXXX...XXXXXXXXXXXXX',), [(...), [... ]]]]]]]
Das Modul base64 Das Codierverfahren base64 wird zur Konvertierung von beliebigen Bin;rdaten in einfachen Text benutzt. Dazu speichert der Codierer jede Gruppe von drei bin;ren Bytes als Gruppe von vier Zeichen aus der folgenden Menge: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789+/
Zus;tzlich wird am Ende des Datenstroms das Zeichen = zum Auffllen benutzt. Beispiel 4-18 zeigt, wie die Funktionen encode und decode auf Dateiobjekten arbeiten.
126
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul base64 Beispiel 4-18: Verwendung des Moduls base64 zur Codierung von Dateien File: base64-example-1.py import base64 MESSAGE = "Leben des Brian" file = open("out.txt", "w") file.write(MESSAGE) file.close() base64.encode(open("out.txt"), open("out.b64", "w")) base64.decode(open("out.b64"), open("out.txt", "w")) print "Original:", repr(MESSAGE) print "codierte Nachricht:", repr(open("out.b64").read()) print "decodierte Nachricht:", repr(open("out.txt").read()) Original: 'Leben des Brian' codierte Nachricht: 'TGViZW4gZGVzIEJyaWFu\012' decodierte Nachricht: 'Leben des Brian'
Beispiel 4-19 zeigt, wie die Funktionen encodestring und decodestring zwischen Strings konvertieren. Die Funktionen sind im Moment als Hllen um encode und decode implementiert, wobei StringIO-Objekte fr die Ein- und Ausgabe benutzt werden. Beispiel 4-19: Verwendung des Moduls base64 zur Codierung von Strings File: base64-example-2.py import base64 MESSAGE = "Leben des Brian" data = base64.encodestring(MESSAGE) original_data = base64.decodestring(data) print "Original:", repr(MESSAGE) print "codierte Nachricht:", repr(data) print "decodierte Nachricht:", repr(original_data) Original: 'Leben des Brian' codierte Nachricht: 'TGViZW4gZGVzIEJyaWFu\012' decodierte Nachricht: 'Leben des Brian'
Beispiel 4-20 zeigt, wie man einen Benutzernamen und ein Paßwort in einen einfachen HTTP-Authentifizierungsstring konvertieren kann. (Man beachte, daß man nicht gerade beim Geheimdienst NSA arbeiten muß, um dieses Format zu decodieren.)
127
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-20: Verwendung des Moduls base64 zur einfachen Authentifizierung File: base64-example-3.py import base64 def getbasic(user, password): # einfache Authentifizierung (gemaess HTTP) return base64.encodestring(user + ":" + password) print getbasic("Aladdin", "Sesam, oeffne Dich") 'QWxhZGRpbjpTZXNhbSwgb2VmZm5lIERpY2g=\012'
Beispiel 4-21 zeigt schließlich ein kleines Werkzeug, das ein GIF-Bild in ein PythonSkript konvertiert, zwecks Verwendung mit der Tkinter-Bibliothek. Beispiel 4-21: Verwendung des Moduls base64 zur Benutzung von GIF-Bildern in Tkinter File: base64-example-4.py import base64, sys if not sys.argv[1:]: print "Usage: gif2tk.py giffile >pyfile" sys.exit(1) data = open(sys.argv[1], "rb").read() if data[:4] != "GIF8": print sys.argv[1], "ist keine GIF-Datei" sys.exit(1) print print print print print print print
'# generiert aus', sys.argv[1], 'von gif2tk.py' 'from Tkinter import PhotoImage' 'image = PhotoImage(data="""' base64.encodestring(data), '""")'
# generiert aus samples/sample.gif von gif2tk.py from Tkinter import PhotoImage image = PhotoImage(data=""" R0lGODlhoAB4APcAAAAAAIAAAACAAICAAAAAgIAAgACAgICAgAQEBIwEBIyMBJRUlISE/LRUBAQE ... AjmQBFmQBnmQCJmQCrmQDNmQDvmQEBmREnkRAQEAOw== """)
128
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul binhex
Das Modul binhex Das in Beispiel 4-22 gezeigte Modul binhex konvertiert in das und aus dem BinHex-Format, das auf dem Macintosh blich ist. Beispiel 4-22: Verwendung des Moduls binhex File: binhex-example-1.py import binhex import sys infile = "samples/sample.jpg" binhex.binhex(infile, sys.stdout) (This file must be converted with BinHex 4.0) :#R0KEA"XC5jUF'F!2j!)!*!%%TS!N!4RdrrBrq!!%%T'58B!!3%!!!%!!3!!rpX !3`!)"JB("J8)"`F(#3N)#J`8$3`,#``C%K-2&"dD(aiG'K`F)#3Z*b!L,#-F(#J h+5``-63d0"mR16di-M`Z-c3brpX!3`%*#3N-#``B$3dB-L%F)6+3-[r!!"%)!)! !J!-")J!#%3%$%3(ra!!I!!!""3'3"J#3#!%#!`3&"JF)#3S,rm3!Y4!!!J%$!`) %!`8&"!3!!!&p!3)$!!34"4)K-8%'%e&K"b*a&$+"ND%))d+a`495dI!N-f*bJJN
Das Modul quopri Das Modul quopri implementiert eine Codierung namens Quoted-Printable gem;ß dem MIME-Standard. Diese Codierung kann dazu verwendet werden, Textnachrichten, die zumeist aus Text in U.S.-ASCII bestehen (z.B. Nachrichten in den meisten europ;ischen Sprachen), in solche Nachrichten zu konvertieren, die nur U.S.-ASCII enthalten. Das kann recht ntzlich sein, wenn Sie Sachen ber dampfgetriebene Postwege an Leute schicken, die Oldtimer-E-Mail-Programme verwenden. Dies wird in Beispiel 4-23 dargestellt. Beispiel 4-23: Verwendung des Moduls quopri File: quopri-example-1.py import quopri import StringIO # Hilfsfunktionen (quopri konvertiert nur Dateien nach Dateien) def encodestring(instring, tabs=0): outfile = StringIO.StringIO() quopri.encode(StringIO.StringIO(instring), outfile, tabs) return outfile.getvalue()
129
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-23: Verwendung des Moduls quopri (Fortsetzung) def decodestring(instring): outfile = StringIO.StringIO() quopri.decode(StringIO.StringIO(instring), outfile) return outfile.getvalue() # ausprobieren MESSAGE = "a i aa _ e ^!" encoded_message = encodestring(MESSAGE) decoded_message = decodestring(encoded_message) print "Original:", MESSAGE print "codierte Nachricht:", repr(encoded_message) print "decodierte Nachricht:", decoded_message Original: b i ba W e T! codierte Nachricht: '=E5 i =E5a =E4 e =F6!\012' decodierte Nachricht: b i ba W e T!
Wie Beispiel 4-23 zeigt, werden von U.S.-ASCII verschiedene Zeichen auf ein Gleichheitszeichen abgebildet (=), gefolgt von zwei hexadezimalen Ziffern. Das gleiche gilt fr das Gleichheitszeichen selbst (»=3D«) wie auch fr Leerzeichen am Zeilenende (»=20«). Alles andere sieht unver;ndert aus. Wenn Sie also nicht allzu viele seltsame Zeichen benutzen, ist der codierte String fast genauso lesbar wie das Original. (Normalerweise hassen Europ;er diese Codierung und sind berzeugt, daß es gewisse amerikanische Programmierer verdienen, wenn man ihnen zur heiteren Musik von Edward German mit einem großen Fisch auf den Kopf haut...)
Das Modul uu Das Codierverfahren uu wird zur Konvertierung von beliebigen Bin;rdaten in einfachen Text verwendet. Dieses Format ist im Usenet ziemlich beliebt, wird jedoch langsam von base64 abgelBst. Ein uu-Codierer wandelt Gruppen von drei Bytes (24 Bits) in eine Sequenz von vier druckbaren Zeichen (6 Bits pro Zeichen) um, wobei Zeichen von chr (32) (Leerzeichen) bis chr (95) verwendet werden. Inklusive L;ngenmarkierung und Zeilenvorschub-Zeichen nimmt die GrBße der mit uu codierten Daten normalerweise um 40 % zu. Ein codierter Datenstrom beginnt mit einer begin-Zeile, die die Dateirechte (den UnixDateimodus als Oktalzahl) sowie den Dateinamen enth;lt, und endet mit einer endZeile: begin 666 sample.jpg M_]C_X 02D9)1@ ! 0 0 ! #_VP!# @&!@<&!0@'!P<)'0@*#!0-# L+ ...more lines like this... end
130
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul uu Das Modul uu stellt zwei Funktionen zur Verfgung: encode und decode. Die in Beispiel 4-24 gezeigte Funktion encode(infile, outfile, filename) codiert Daten aus der Eingabedatei und schreibt sie in die Ausgabedatei. Die Dateiargumente fr Ein- und Ausgabe kBnnen entweder Dateinamen oder Dateiobjekte sein. Das dritte Argument wird als Dateiname im Feld begin verwendet. Beispiel 4-24: Verwendung des Moduls uu zur Codierung einer BinBrdatei File: uu-example-1.py import uu import os, sys infile = "samples/sample.jpg" uu.encode(infile, sys.stdout, os.path.basename(infile)) begin 666 sample.jpg M_]C_X 02D9)1@ ! 0 0 ! #_VP!# @&!@<&!0@'!P<)"0@*#!0-# L+ M#!D2$P\4'1H?'AT:'!P@)"XG("(L(QP<*#
Die in Beispiel 4-25 gezeigte Funktion decode(infile, outfile) decodiert uu-codierte Daten aus dem Text der Eingabedatei und schreibt sie in die Ausgabedatei. Wieder kBnnen beide Argumente entweder Dateinamen oder -objekte sein. Beispiel 4-25: Verwendung des Moduls uu zur Decodierung einer uu-codierten Datei File: uu-example-2.py import uu import StringIO infile = "samples/sample.uue" outfile = "samples/sample.jpg" # # decodiere fi = open(infile) fo = StringIO.StringIO() uu.decode(fi, fo) # # vergleiche mit Originaldatei data = open(outfile, "rb").read()
131
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 4: DatenreprBsentation Beispiel 4-25: Verwendung des Moduls uu zur Decodierung einer uu-codierten Datei (Fortsetzung) if fo.getvalue() == data: print len(data), "Bytes ok"
Das Modul binascii Das in Beispiel 4-26 gezeigte Modul binascii enth;lt Hilfsfunktionen fr eine Reihe von Codiermodulen, darunter base64, binhex und uu. Ab 2.0 ermBglicht das Modul auch, Bin;rdaten in und aus hexadezimalen Strings zu konvertieren. Beispiel 4-26: Verwendung des Moduls binascii File: binascii-example-1.py import binascii text = "Hallo Frau Ente" data = binascii.b2a_base64(text) text = binascii.a2b_base64(data) print text, "<=>", repr(data) data = binascii.b2a_uu(text) text = binascii.a2b_uu(data) print text, "<=>", repr(data) data = binascii.b2a_hqx(text) text = binascii.a2b_hqx(data)[0] print text, "<=>", repr(data) # 2.0 und spaeter data = binascii.b2a_hex(text) text = binascii.a2b_hex(data) print text, "<=>", repr(data) Hallo Hallo Hallo Hallo
132
Frau Frau Frau Frau
Ente Ente Ente Ente
<=> <=> <=> <=>
'SGFsbG8gRnJhdSBFbnRl\012' '/2&%L;&\\@1G)A=2!%;G1E\012' '5\'&XE\'mJ4R*KG5"&ER4P' '48616c6c6f204672617520456e7465'
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
5 Dateiformate 1bersicht Dieses Kapitel beschreibt eine Reihe von Modulen zum Parsen verschiedener Dateiformate.
Auszeichnungssprachen Python verfgt ber eine umfangreiche Untersttzung der Dateiformate XML (Extensible Markup Language) und HTML (Hypertext Markup Language). Außerdem bietet Python eine einfache Untersttzung fr SGML (Standard Generalized Markup Language). All diese Formate besitzen die gleiche Grundstruktur, da sowohl HTML als auch XML von SGML abgeleitet sind. Jedes Dokument besteht aus einer Mischung von Start-Tags, End-Tags, einfachem Text (auch »character data« genannt) und Entity-Referenzen, wie im folgenden gezeigt: <document name="sample.xml"> Dies ist ein Header Dies ist der Body-Text. Der Text kann einfachen Text ("character data"), Tags und Entities enthalten.
Im vorigen Beispiel sind <document>, und Start-Tags. Zu jedem StartTag gibt es ein entsprechendes End-Tag, das ;hnlich aussieht, aber vor dem Tag-Namen einen Schr;gstrich hat. Das Start-Tag kann auch ein oder mehrere Attribute enthalten, hier z.B. das Attribut name. Alles zwischen einem Start-Tag und seinem entsprechenden End-Tag wird ein Element genannt. Im vorigen Beispiel enth;lt das Element document zwei andere Elemente: header und body.
133
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Schließlich ist " ein Zeichen-Entity. Es wird benutzt, um in den Textabschnitten reservierte Zeichen darzustellen. In diesem Fall ist es ein Kaufmanns-Und (&, engl. Ampersand), das seinerseits benutzt wird, um das Entity selbst einzuleiten. Andere h;ufige Entities sind < fr »less than«, d.h. »kleiner als« (<), und > fr »greater than«, d.h. »grBßer als« (>). Obwohl XML, HTML und SGML aus den gleichen Grundbausteinen bestehen, gibt es doch wichtige Unterschiede. In XML mssen alle Elemente Start- und End-Tags haben, und diese mssen korrekt verschachtelt sein (sind sie das, spricht man von einem wohlgeformten Dokument). Außerdem ist in XML die Groß-/Kleinschreibung relevant, d.h., <document> und sind zwei verschiedene Elemente. HTML hingegen ist etwas toleranter. Der HTML-Parser kann oftmals fehlende Tags einfgen. Wenn Sie z.B. in HTML einen neuen Absatz mit dem Tag beginnen, ohne den vorherigen Absatz zu schließen, fgt der Parser automatisch ein End-Tag
ein. Außerdem ist in HTML auch die Groß-/Kleinschreibung der Tag- und attribut-Namen egal. Andererseits erlaubt Ihnen XML, Ihre eigenen Elemente zu definieren, w;hrend HTML einen festen Satz von Elementen verwendet, der in der HTML-Spezifikation definiert ist. SGML ist sogar noch flexibler. In seiner vollst;ndigen Auspr;gung kBnnen Sie eine spezifische Deklaration verwenden, um zu definieren, wie der Quelltext in eine Elementstruktur zu bersetzen ist, und eine DTD (Document Type Definition), um die Struktur zu validieren und fehlende Tags zu erg;nzen. Technisch gesehen sind HTML und XML beide SGML-Anwendungen ; beide haben ihre eigene SGML-Deklaration, und HTML hat auch eine Standard-DTD. Python bietet Parser fr alle Varianten dieser Auszeichnungssprachen. Obwohl SGML das flexibelste dieser Formate ist, ist Pythons SGML-Parser in sgmllib tats;chlich sehr einfach. Er umgeht die meisten Probleme, indem er gerade so viel vom SGML-Standard versteht, um mit HTML umgehen zu kBnnen. Er beherrscht auch keine DTDs. Statt dessen kann man den Parser durch Bildung von Unterklassen anpassen. Pythons HTML-Untersttzung baut auf dem SGML-Parser auf. Der Parser htmllib delegiert die eigentliche Darstellung an ein Formatierobjekt. Das Modul formatter enth;lt eine Reihe von Standardformatierern. Die XML-Untersttzung in Python ist ;ußerst komplex. In Python 1.5.2 war die verfgbare Untersttzung auf den Parser im Modul xmllib beschr;nkt, dem Modul sgmllib sehr ;hnlich (mit einem wichtigen Unterschied jedoch: xmllib versucht, den gesamten XML-Standard zu untersttzen). Zu Python 2.0 gehBren fortschrittlichere XML-Werkzeuge, die auf dem optionalen Parser in expat aufbauen.
Konfigurationsdateien Das Modul ConfigParser liest und schreibt ein einfaches Konfigurationsdateiformat, ;hnlich den INI-Dateien in Windows.
134
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul xmllib Das Modul netrc liest .netrc-Konfigurationsdateien, und mit dem Modul shlex kann eine beliebige Konfigurationsdatei mit Hilfe einer Shell-Skript-;hnlichen Syntax gelesen werden.
Archivierungsformate Pythons Standardbibliothek untersttzt die popul;ren Formate GZIP und ZIP (nur in 2.0). Das Modul gzip und zipfile liest und schreibt GZIP-Dateien, ZIP-Dateien. Beide Module sind abh;ngig vom Datenkomprimierungsmodul zlib.
Das Modul xmllib Das Modul xmllib bietet einen einfachen XML-Parser, der XML-Daten mit regul;ren Ausdrcken bearbeitet, wie in Beispiel 5-1 gezeigt. Der Parser fhrt einfache Prfungen auf dem Dokument durch, z.B. prft er, ob nur ein Element auf der obersten Ebene existiert und ob alle Tags durch End-Tags beendet sind. An diesen Parser bergeben Sie stckweise XML-Daten (so wie sie z.B. ber ein Netzwerk ankommen). Der Parser ruft eigene Methoden auf, unter anderem fr Start-Tags, Datenabschnitte, End-Tags und Entities. Wenn Sie nur an einigen Tags interessiert sind, kBnnen Sie spezielle Methoden namens start_tag und end_tag definieren, wobei tag der Name des Tags ist. Beim Aufruf der start-Funktionen werden die Attribute als Dictionary bergeben. Beispiel 5-1: Verwendung des Moduls xmllib zum Auslesen von Informationen aus einem Element File: xmllib-example-1.py import xmllib class Parser(xmllib.XMLParser): # Quotation-Zahl ermitteln def __init__(self, file=None): xmllib.XMLParser.__init__(self) if file: self.load(file) def load(self, file): while 1: s = file.read(512) if not s: break self.feed(s) self.close()
135
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-1: Verwendung des Moduls xmllib zum Auslesen von Informationen aus einem Element (Fortsetzung) def start_quotation(self, attrs): print "id =>", attrs.get("id") raise EOFError try: c = Parser() c.load(open("samples/sample.xml")) except EOFError: pass id => 031
Beispiel 5-2 enth;lt eine einfache (und unvollst;ndige) Rendering-Engine. Der Parser verwaltet einen Stapel von Elementen namens ( _ _tags), den er zusammen mit Textfragmenten an den Renderer bergibt. Der Renderer schaut in einem Stil-Dictionary nach der aktuellen Tag-Hierarchie und, falls sie noch nicht enthalten ist, erzeugt einen neuen Stil-Deskriptor, indem er Teile des Stylesheets zusammensetzt. Beispiel 5-2: Verwendung des Moduls xmllib File: xmllib-example-2.py import xmllib import string, sys STYLESHEET = { # jedes Element kann ein oder mehrere Style-Elemente beitragen "quotation": {"style": "italic"}, "lang": {"weight": "bold"}, "name": {"weight": "medium"}, } class Parser(xmllib.XMLParser): # eine einfache Style-Maschine def __init__(self, renderer): xmllib.XMLParser.__init__(self) self.__data = [] self.__tags = [] self.__renderer = renderer def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close()
136
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul xmllib Beispiel 5-2: Verwendung des Moduls xmllib (Fortsetzung) def handle_data(self, data): self.__data.append(data) def unknown_starttag(self, tag, attrs): if self.__data: text = string.join(self.__data, "") self.__renderer.text(self.__tags, text) self.__tags.append(tag) self.__data = [] def unknown_endtag(self, tag): self.__tags.pop() if self.__data: text = string.join(self.__data, "") self.__renderer.text(self.__tags, text) self.__data = [] class DumbRenderer: def __init__(self): self.cache = {} def text(self, tags, text): # gib Text in dem Style aus, der vom Tag-Stapel angegeben wird tags = tuple(tags) style = self.cache.get(tags) if style is None: # finde einen kombinierten Style style = {} for tag in tags: s = STYLESHEET.get(tag) if s: style.update(s) self.cache[tags] = style # aktualisiere Cache # schreibe auf Standardausgabe sys.stdout.write("%s =>\n" % style) sys.stdout.write(" " + repr(text) + "\n") # ausprobieren r = DumbRenderer() c = Parser(r) c.load(open("samples/sample.xml")) {'style': 'italic'} => 'I\'ve had a lot of developers come up to me and\012say, "I haven\'t had this much fun in a long time. It sure beats\012writing ' {'style': 'italic', 'weight': 'bold'} => 'Cobol' {'style': 'italic'} => '" -- '
137
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-2: Verwendung des Moduls xmllib (Fortsetzung) {'style': 'italic', 'weight': 'medium'} => 'James Gosling' {'style': 'italic'} => ', on\012' {'weight': 'bold'} => 'Java' {'style': 'italic'} => '.'
Das Modul xml.parsers.expat (Optional) Das Modul xml.parsers.expat ist eine Schnittstelle zu James Clarks XMLParser Expat. Beispiel 5-3 demonstriert die Anwendung dieses umfangreichen und schnellen Parsers, der vortrefflich fr eine Produktionsumgebung geeignet ist. Beispiel 5-3: Verwendung des Moduls xml.parsers.expat File: xml-parsers-expat-example-1.py from xml.parsers import expat class Parser: def __init__(self): self._parser = expat.ParserCreate() self._parser.StartElementHandler = self.start self._parser.EndElementHandler = self.end self._parser.CharacterDataHandler = self.data def feed(self, data): self._parser.Parse(data, 0) def close(self): self._parser.Parse("", 1) # Ende der Daten del self._parser # werde zirkulaere Verweise los def start(self, tag, attrs): print "START", repr(tag), attrs def end(self, tag): print "END", repr(tag) def data(self, data): print "DATA", repr(data) p = Parser() p.feed("data ") p.close()
138
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul xml.parsers.expat Beispiel 5-3: Verwendung des Moduls xml.parsers.expat (Fortsetzung) START u'tag' {} DATA u'data' END u'tag'
Man beachte, daß der Parser Unicode-Strings zurckgibt, selbst wenn man ihm gewBhnlichen Text bergibt. Per Voreinstellung interpretiert der Parser den Quelltext als UTF-8 (wie es der XML-Standard vorgibt). Bei Verwendung anderer Codierungen sollte man sicherstellen, daß die XML-Datei eine encoding-Direktive enth;lt. Beispiel 5-4 zeigt, wie man einen Text in ISO Latin-1 mit xml.parsers.expat liest. Beispiel 5-4: Verwendung des Moduls xml.parsers.expat zum Lesen von Text in ISO Latin-1 File: xml-parsers-expat-example-2.py from xml.parsers import expat class Parser: def __init__(self): self._parser = expat.ParserCreate() self._parser.StartElementHandler = self.start self._parser.EndElementHandler = self.end self._parser.CharacterDataHandler = self.data def feed(self, data): self._parser.Parse(data, 0) def close(self): self._parser.Parse("", 1) # Ende der Daten del self._parser # werde zirkulaere Verweise los def start(self, tag, attrs): print "START", repr(tag), attrs def end(self, tag): print "END", repr(tag) def data(self, data): print "DATA", repr(data) p = Parser() p.feed("""\ fredrik lundh link^ping """ ) p.close()
139
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-4: Verwendung des Moduls xml.parsers.expat zum Lesen von Text in ISO Latin-1 (Fortsetzung) START u'author' {} DATA u'\012' START u'name' {} DATA u'fredrik lundh' END u'name' DATA u'\012' START u'city' {} DATA u'link\366ping' END u'city' DATA u'\012' END u'author'
Das Modul sgmllib Das in Beispiel 5-5 gezeigte Modul sgmllib enth;lt einen einfachen SGML-Parser. Er arbeitet ziemlich ;hnlich wie der Parser xmllib, macht jedoch weniger Einschr;nkungen (und ist auch weniger vollst;ndig). Wie in xmllib ruft dieser Parser eigene Methoden auf, um mit Dingen wie Start-Tags, Datenabschnitten, End-Tags und Entities arbeiten zu kBnnen. Wenn Sie nur an bestimmten Tags interessiert sind, kBnnen Sie spezielle start- und end-Methoden definieren. Beispiel 5-5: Verwendung des Moduls sgmllib zum Auslesen des Title-Elements File: sgmllib-example-1.py import sgmllib import string class FoundTitle(Exception): pass class ExtractTitle(sgmllib.SGMLParser): def __init__(self, verbose=0): sgmllib.SGMLParser.__init__(self, verbose) self.title = self.data = None def handle_data(self, data): if self.data is not None: self.data.append(data) def start_title(self, attrs): self.data = [] def end_title(self): self.title = string.join(self.data, "") raise FoundTitle # Abbruch des Parsens!
140
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sgmllib Beispiel 5-5: Verwendung des Moduls sgmllib zum Auslesen des Title-Elements (Fortsetzung) def extract(file): # extrahiere Titel aus einem HTML/SGML-Strom p = ExtractTitle() try: while 1: # lies kleine Happen s = file.read(512) if not s: break p.feed(s) p.close() except FoundTitle: return p.title return None # # ausprobieren print "html", "=>", extract(open("samples/sample.htm")) print "sgml", "=>", extract(open("samples/sample.sgm")) html => A Title. sgml => Quotations
Um alle Tags zu behandeln, berschreiben Sie statt dessen die Methoden unknown_ starttag und unknown_endtag, wie in Beispiel 5-6 gezeigt. Beispiel 5-6: Verwendung des Moduls sgmllib zur Formatierung eines SGML-Dokuments File: sgmllib-example-2.py import sgmllib import cgi, sys class PrettyPrinter(sgmllib.SGMLParser): # ein einfacher SGML Pretty Printer def __init__(self): # initialisiere Oberklasse sgmllib.SGMLParser.__init__(self) self.flag = 0 def newline(self): # erzwinge Zeilenende, wenn noetig if self.flag: sys.stdout.write("\n") self.flag = 0 def unknown_starttag(self, tag, attrs): # wird fuer jedes Start-Tag aufgerufen
141
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-6: Verwendung des Moduls sgmllib zur Formatierung eines SGML-Dokuments (Fortsetzung) # Das Argument attrs ist eine Liste von (attr, value)-Tupeln. # Wandle es in einen String. text = "" for attr, value in attrs: text = text + " %s='%s'" % (attr, cgi.escape(value)) self.newline() sys.stdout.write("<%s%s>\n" % (tag, text)) def handle_data(self, text): # wird fuer jeden Textabschnitt aufgerufen sys.stdout.write(text) self.flag = (text[-1:] != "\n") def handle_entityref(self, text): # wird fuer jedes Entity aufgerufen sys.stdout.write("&%s;" % text) def unknown_endtag(self, tag): # wird fuer jedes End-Tag aufgerufen self.newline() sys.stdout.write("<%s>" % tag) # # ausprobieren file = open("samples/sample.sgm") p = PrettyPrinter() p.feed(file.read()) p.close() Quotations <epigraph> eff-bot, June 1997 <para> Nobody expects the Spanish Inquisition! Amongst our weaponry are such diverse elements as fear, surprise, ruthless efficiency, and an almost fanatical devotion to Guido, and nice red uniforms — oh, damn!
142
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul sgmllib Beispiel 5-6: Verwendung des Moduls sgmllib zur Formatierung eines SGML-Dokuments (Fortsetzung) <para> <epigraph>
In Beispiel 5-7 wird geprft, ob ein SGML-Dokument im XML-Sinn »wohlgeformt« ist. In einem wohlgeformten Dokument sind alle Elemente korrekt verschachtelt, mit je einem End-Tag fr jedes Start-Tag. Um dies zu prfen, arbeiten wir einfach mit einer Liste von Bffnenden Tags und prfen, daß jedes End-Tag ein entsprechendes Start-Tag abschließt und daß keine Bffnenden Tags mehr brig sind, wenn wir das Ende des Dokuments erreichen. Beispiel 5-7: Verwendung des Moduls sgmllib zur 5berpr6fung der Wohlgeformtheit File: sgmllib-example-3.py import sgmllib class WellFormednessChecker(sgmllib.SGMLParser): # Prueft, ob ein SGML-Dokument 'wohlgeformt' ist # (im XML-Sinn). def __init__(self, file=None): sgmllib.SGMLParser.__init__(self) self.tags = [] if file: self.load(file) def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close() def close(self): sgmllib.SGMLParser.close(self) if self.tags: raise SyntaxError, "Start-Tag %s nicht geschlossen" % self.tags[-1] def unknown_starttag(self, start, attrs): self.tags.append(start) def unknown_endtag(self, end): start = self.tags.pop() if end != start: raise SyntaxError, "End-Tag %s passt nicht zu Start-Tag %s" %\ (end, start)
143
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-7: Verwendung des Moduls sgmllib zur 5berpr6fung der Wohlgeformtheit (Fortsetzung) try: c = WellFormednessChecker() c.load(open("samples/sample.htm")) except SyntaxError: raise # gib Fehler aus else: print "Dokument ist wohlgeformt" Traceback (innermost last): ... SyntaxError: End-Tag head passt nicht zu Start-Tag meta
Beispiel 5-8 zeigt schließlich eine Klasse, die es Ihnen ermBglicht, HTML- und SGMLDokumente zu filtern. Um sie zu benutzen, leiten Sie davon Ihre eigene Unterklasse ab und implementieren Sie die Methoden start und end. Beispiel 5-8: Verwendung des Moduls sgmllib zum Filtern von SGML-Dokumenten File: sgmllib-example-4.py import sgmllib import cgi, string, sys class SGMLFilter(sgmllib.SGMLParser): # SGML-Filter. Ueberschreibt start/end, # um Dokument-Elemente zu bearbeiten def __init__(self, outfile=None, infile=None): sgmllib.SGMLParser.__init__(self) if not outfile: outfile = sys.stdout self.write = outfile.write if infile: self.load(infile) def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close() def handle_entityref(self, name): self.write("&%s;" % name) def handle_data(self, data): self.write(cgi.escape(data))
144
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul htmllib Beispiel 5-8: Verwendung des Moduls sgmllib zum Filtern von SGML-Dokumenten (Fortsetzung) def unknown_starttag(self, tag, attrs): tag, attrs = self.start(tag, attrs) if tag: if not attrs: self.write("<%s>" % tag) else: self.write("<%s" % tag) for k, v in attrs: self.write(" %s=%s" % (k, repr(v))) self.write(">") def unknown_endtag(self, tag): tag = self.end(tag) if tag: self.write("%s>" % tag) def start(self, tag, attrs): return tag, attrs # ueberschreiben def end(self, tag): return tag # ueberschreiben class Filter(SGMLFilter): def fixtag(self, tag): if tag == "em": tag = "i" if tag == "string": tag = "b" return string.upper(tag) def start(self, tag, attrs): return self.fixtag(tag), attrs def end(self, tag): return self.fixtag(tag) c = Filter() c.load(open("samples/sample.htm"))
Das Modul htmllib Das Modul htmllib enth;lt einen Tag-getriebenen HTML-Parser, der Daten an ein Formatierungsobjekt sendet. Beispiel 5-9 verwendet dieses Modul. Weitere Beispiele dazu, wie man HTML-Dateien mit diesem Modul parsen kann, findet man in der Beschreibung zum Modul formatter.
145
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-9: Verwendung des Moduls htmllib File: htmllib-example-1.py import htmllib import formatter import string class Parser(htmllib.HTMLParser): # gibt ein Dictionary zurueck, das Anker-Texte auf # Listen von zugehoerigen Hyperlinks abbildet def __init__(self, verbose=0): self.anchors = {} f = formatter.NullFormatter() htmllib.HTMLParser.__init__(self, f, verbose) def anchor_bgn(self, href, name, type): self.save_bgn() self.anchor = href def anchor_end(self): text = string.strip(self.save_end()) if self.anchor and text: self.anchors[text] = self.anchors.get(text, []) + [self.anchor] file = open("samples/sample.htm") html = file.read() file.close() p = Parser() p.feed(html) p.close() for k, v in p.anchors.items(): print k, "=>", v print link => ['http://www.python.org']
Wenn Sie eine HTML-Datei nur parsen, aber nicht auf einem Ausgabeger;t darstellen mssen, ist es normalerweise einfacher, statt dessen das Modul sgmllib zu benutzen.
Das Modul htmlentitydefs Das Modul htmlentitydefs enth;lt ein Dictionary mit vielen Zeichen-Entities aus ISO Latin-1, die von HTML benutzt werden. Wie man es verwendet, wird in Beispiel 5-10 gezeigt.
146
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul htmlentitydefs Beispiel 5-10: Verwendung des Moduls htmlentitydefs File: htmlentitydefs-example-1.py import htmlentitydefs entities = htmlentitydefs.entitydefs for entity in "amp", "quot", "copy", "yen": print entity, "=", entities[entity] amp = & quot = " copy = ` yen = ¥
Beispiel 5-11 zeigt, wie man regul;re Ausdrcke mit diesem Dictionary kombinieren kann, um Entities in einen String zu bersetzen (das Gegenteil von cgi.escape). Beispiel 5-11: Verwendung des Moduls htmlentitydefs zum 5bersetzen von Entities File: htmlentitydefs-example-2.py import htmlentitydefs import re import cgi pattern = re.compile("&(\w+?);") def descape_entity(m, defs=htmlentitydefs.entitydefs): # Callback: uebersetze ein Entity in seinen ISO-Latin-Wert try: return defs[m.group(1)] except KeyError: return m.group(0) # als solches verwenden def descape(string): return pattern.sub(descape_entity, string) print descape("<spam&eggs>") print descape(cgi.escape("<spam&eggs>")) <spam&eggs> <spam&eggs>
Beispiel 5-12 zeigt schließlich, wie man in XML und ISO Latin-1 reservierte Zeichen in einen XML-String bersetzt. Dies funktioniert ;hnlich wie bei cgi.escape, ersetzt jedoch auch Nicht-ASCII-Zeichen.
147
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-12: Maskierung von Entities in ISO Latin-1 File: htmlentitydefs-example-3.py import htmlentitydefs import re, string # dieses Muster passt auf Unterstrings von reservierten # und Nicht-ASCII-Zeichen pattern = re.compile(r"[&<>\"\x80-\xff]+") # erzeuge Zeichen-Abbildung entity_map = {} for i in range(256): entity_map[chr(i)] = "&%d;" % i for entity, char in htmlentitydefs.entitydefs.items(): if entity_map.has_key(char): entity_map[char] = "&%s;" % entity def escape_entity(m, get=entity_map.get): return string.join(map(get, m.group()), "") def escape(string): return pattern.sub(escape_entity, string) print escape("<spam&eggs>") print escape("a i aa _ e ^") <spam&eggs> å i åa ä e ö
Das Modul formatter Das Modul formatter enth;lt Formatierungsklassen, die gemeinsam mit dem Modul htmllib verwendet werden kBnnen. In diesem Modul befinden sich zwei Familien von Klassen, Formatierer und Schreiber. Formatierer konvertieren eine Folge von Tags und Datenstrings aus dem HTML-Parser in eine Folge von Ereignissen, die fr ein Ausgabeger;t geeignet ist, und Schreiber stellen diese Ereignisfolge auf einem Ausgabeger;t dar. Beispiel 5-13 demonstriert dies. In den meisten F;llen kBnnen Sie die Formatierung mit der Klasse AbstractFormatter vornehmen. Sie ruft Methoden auf dem Schreiber-Objekt auf, die verschiedene Formatierungsereignisse repr;sentieren. Die Klasse AbstractWriter gibt fr jeden Methodenaufruf einfach nur eine Nachricht aus.
148
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul formatter Beispiel 5-13: Verwendung des Moduls formatter zur Umwandlung von HTML in Ereignisfolgen File: formatter-example-1.py import formatter import htmllib w = formatter.AbstractWriter() f = formatter.AbstractFormatter(w) file = open("samples/sample.htm") p = htmllib.HTMLParser(f) p.feed(file.read()) p.close() file.close() send_paragraph(1) new_font(('h1', 0, 1, 0)) send_flowing_data('A Chapter.') send_line_break() send_paragraph(1) new_font(None) send_flowing_data('Some text. Some more text. Some') send_flowing_data(' ') new_font((None, 1, None, None)) send_flowing_data('emphasised') new_font(None) send_flowing_data(' text. A') send_flowing_data(' link') send_flowing_data('[1]') send_flowing_data('.')
Zus;tzlich zur Klasse AbstractWriter enth;lt das Modul formatter die Klasse NullWriter, die alle an sie bergebenen Ereignisse ignoriert, und die Klasse DumbWriter, die die Ereignisfolge in ein einfaches Textdokument konvertiert, wie in Beispiel 5-14 gezeigt. Beispiel 5-14: Verwendung des Moduls formatter zur Umwandlung von HTML in Text File: formatter-example-2.py import formatter import htmllib w = formatter.DumbWriter() # einfacher Text f = formatter.AbstractFormatter(w) file = open("samples/sample.htm") # gib HTML-Body als einfachen Text aus p = htmllib.HTMLParser(f) p.feed(file.read())
149
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-14: Verwendung des Moduls formatter zur Umwandlung von HTML in Text (Fortsetzung) p.close() file.close() # gib Links aus print print i = 1 for link in p.anchorlist: print i, "=>", link i = i + 1 A Chapter. Some text. Some more text. Some emphasised text. A link[1]. 1 => http://www.python.org
Beispiel 5-15 enth;lt einen spezifischen Writer, der in diesem Fall von der Klasse DumbWriter abgeleitet ist. Diese Version beachtet die aktuelle Schriftart und biegt in Abh;ngigkeit davon die Ausgabe ein wenig zurecht. Beispiel 5-15: Verwendung des Moduls formatter mit einem spezifischen Schreiber File: formatter-example-3.py import formatter import htmllib, string class Writer(formatter.DumbWriter): def __init__(self): formatter.DumbWriter.__init__(self) self.tag = "" self.bold = self.italic = 0 self.fonts = [] def new_font(self, font): if font is None: font = self.fonts.pop() self.tag, self.bold, self.italic = font else: self.fonts.append((self.tag, self.bold, self.italic)) tag, bold, italic, typewriter = font if tag is not None: self.tag = tag if bold is not None: self.bold = bold if italic is not None: self.italic = italic
150
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul ConfigParser Beispiel 5-15: Verwendung des Moduls formatter mit einem spezifischen Schreiber (Fortsetzung) def send_flowing_data(self, data): if not data: return atbreak = self.atbreak or data[0] in string.whitespace for word in string.split(data): if atbreak: self.file.write(" ") if self.tag in ("h1", "h2", "h3"): word = string.upper(word) if self.bold: word = "*" + word + "*" if self.italic: word = "_" + word + "_" self.file.write(word) atbreak = 1 self.atbreak = data[-1] in string.whitespace w = Writer() f = formatter.AbstractFormatter(w) file = open("samples/sample.htm") # gib HTML-Body als einfachen Text aus p = htmllib.HTMLParser(f) p.feed(file.read()) p.close() _A_ _CHAPTER._ Some text. Some more text. Some *emphasised* text. A link[1].
Das Modul ConfigParser Das Modul ConfigParser liest Konfigurationsdateien. Die Dateien sollten in einem Format sein, das dem von INI-Dateien in Windows ;hnlich ist. Eine Datei enth;lt einen oder mehrere Abschnitte, die durch Namen in eckigen Klammern voneinander getrennt sind. Jeder Abschnitt kann einen oder mehrere Konfigurationseintr;ge haben. Dies ist die in Beispiel 5-16 verwendete Datei: [book] title: The Python Standard Library author: Fredrik Lundh email: fredrik@pythonware.com version: 2.0-001115 [ematter] pages: 250
151
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate [hardcopy] pages: 350
Beispiel 5-16 benutzt das Modul ConfigParser, um die Beispielkonfigurationsdatei zu lesen. Beispiel 5-16: Verwendung des Moduls ConfigParser File: configparser-example-1.py import ConfigParser import string config = ConfigParser.ConfigParser() config.read("samples/sample.ini") # Zusammenfassung ausgeben print print string.upper(config.get("book", "title")) print "by", config.get("book", "author"), print "(" + config.get("book", "email") + ")" print print config.get("ematter", "pages"), "pages" print # gesamte Konfigurationsdatei ausgeben for section in config.sections(): print section for option in config.options(section): print " ", option, "=", config.get(section, option) THE PYTHON STANDARD LIBRARY by Fredrik Lundh (fredrik@pythonware.com) 250 pages book title = Python Standard Library email = fredrik@pythonware.com author = Fredrik Lundh version = 2.0-001115 __name__ = book ematter __name__ = ematter pages = 250 hardcopy __name__ = hardcopy pages = 350
152
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul netrc In Python 2.0 ermBglicht das Modul ConfigParser zudem, Konfigurationsdaten in eine Datei zu schreiben, wie in Beispiel 5-17 gezeigt. Beispiel 5-17: Verwendung des Moduls ConfigParser zum Schreiben von Konfigurationsdateien File: configparser-example-2.py import ConfigParser import sys config = ConfigParser.ConfigParser() # setze eine Reihe von Parametern config.add_section("book") config.set("book", "title", "the python standard library") config.set("book", "author", "fredrik lundh") config.add_section("ematter") config.set("ematter", "pages", 250) # gib auf den Bildschirm aus config.write(sys.stdout) [book] title = the python standard library author = fredrik lundh [ematter] pages = 250
Das Modul netrc Das Modul netrc parst .netrc-Konfigurationsdateien, wie in Beispiel 5-18 gezeigt. Solche Dateien werden verwendet, um FTP-Benutzernamen und -PaßwBrter im Home-Verzeichnis eines Benutzers zu speichern (vergessen Sie nicht, es so einzurichten, daß die Datei nur vom Benutzer gelesen werden kann: chmod 0600 ~/.netrc). Beispiel 5-18: Verwendung des Moduls netrc File: netrc-example-1.py import netrc # Voreinstellung ist $HOME/.netrc info = netrc.netrc("samples/sample.netrc") login, account, password = info.authenticators("secret.fbi") print "Login-Name", "=>", repr(login) print "Account", "=>", repr(account) print "Passwort", "=>", repr(password)
153
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-18: Verwendung des Moduls netrc (Fortsetzung) Login-Name => 'mulder' Account => None Passwort => 'trustno1'
Das Modul shlex Das Modul shlex enth;lt einen einfachen Lexer (auch als Tokenizer bekannt) fr Sprachen, deren Syntax auf der von Unix-Shells basiert. Seine Verwendung wird in Beispiel 5-19 gezeigt. Beispiel 5-19: Verwendung des Moduls shlex File: shlex-example-1.py import shlex lexer = shlex.shlex(open("samples/sample.netrc", "r")) lexer.wordchars = lexer.wordchars + "._" while 1: token = lexer.get_token() if not token: break print repr(token) 'machine' 'secret.fbi' 'login' 'mulder' 'password' 'trustno1' 'machine' 'non.secret.fbi' 'login' 'scully' 'password' 'noway'
Das Modul zipfile (Neu in 2.0) Das Modul zipfile ermBglicht es, Dateien im popul;ren ZIP-Archivformat zu lesen und zu schreiben.
154
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul zipfile
Auflistung des Inhalts Um den Inhalt eines existierenden Archivs aufzulisten, kBnnen Sie die in Beispiel 5-20 verwendeten Methoden namelist und infolist benutzen. Erstere gibt eine Liste von Dateinamen und letztere eine Liste von ZipInfo -Instanzen zurck. Beispiel 5-20: Verwendung des Moduls zipfile zur Auflistung von Dateien in einer ZIP-Datei File: zipfile-example-1.py import zipfile file = zipfile.ZipFile("samples/sample.zip", "r") # Dateinamen auflisten for name in file.namelist(): print name, print # Dateiinformationen ausgeben for info in file.infolist(): print info.filename, info.date_time, info.file_size sample.txt sample.jpg sample.txt (1999, 9, 11, 20, 11, 8) 302 sample.jpg (1999, 9, 18, 16, 9, 44) 4762
Auslesen von Daten aus einer ZIP-Datei Um Daten aus einem Archiv auszulesen, verwenden Sie einfach die in Beispiel 5-21 benutzte Methode read. Sie erwartet einen Dateinamen als Argument und gibt die Daten als String zurck. Beispiel 5-21: Verwendung des Moduls zipfile zum Auslesen von Daten aus einer ZIP-Datei File: zipfile-example-2.py import zipfile file = zipfile.ZipFile("samples/sample.zip", "r") for name in file.namelist(): data = file.read(name) print name, len(data), repr(data[:10]) sample.txt 302 'We will pe' sample.jpg 4762 '\377\330\377\340\000\020JFIF'
155
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate
Schreiben von Daten in eine ZIP-Datei Dateien zu einem Archiv hinzuzufgen ist einfach. $bergeben Sie dazu nur den Dateinamen sowie den Namen, den die Datei im Archiv haben soll, an die Methode write. Das Skript in Beispiel 5-22 erzeugt eine ZIP-Datei mit allen Dateien im Verzeichnis samples.
Beispiel 5-22: Verwendung des Moduls zipfile zum Speichern von Dateien in einer ZIP-Datei File: zipfile-example-3.py import zipfile import glob, os # oeffne die ZIP-Datei zum Schreiben und schreibe etwas rein file = zipfile.ZipFile("test.zip", "w") for name in glob.glob("samples/*"): file.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED) file.close() # oeffne die Datei erneut, um zu sehen, was drin ist file = zipfile.ZipFile("test.zip", "r") for info in file.infolist(): print info.filename, info.date_time, info.file_size, info.compress_size sample.wav (1999, 8, 15, 21, 26, 46) 13260 10985 sample.jpg (1999, 9, 18, 16, 9, 44) 4762 4626 sample.au (1999, 7, 18, 20, 57, 34) 1676 1103 ...
Das dritte, optionale Argument der Methode write gibt die zu verwendende Komprimierungsart an bzw. bestimmt, ob Daten berhaupt komprimiert werden sollen. Die Voreinstellung ist zipfile.ZIP_STORED, wobei Daten ohne jede Komprimierung im Archiv gespeichert werden. Wenn das Modul zlib installiert ist, kBnnen Sie auch zipfile.ZIP_DEFLATED verwenden, wobei dann mit dem Verfahren »deflate« komprimiert wird. Das Modul zipfile ermBglicht es auch, Strings ins Archiv zu bernehmen. Allerdings ist das Hinzufgen von Daten aus Strings recht knifflig. Anstatt nur den Archivnamen und die Daten anzugeben, mssen Sie eine ZipInfo-Instanz erzeugen und korrekt konfigurieren. Beispiel 5-23 bietet eine einfachere LBsung.
156
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul gzip Beispiel 5-23: Verwendung des Moduls zipfile zum Speichern von Strings in einer ZIP-Datei File: zipfile-example-4.py import zipfile import glob, os, time file = zipfile.ZipFile("test.zip", "w") now = time.localtime(time.time())[:6] for name in ("life", "of", "brian"): info = zipfile.ZipInfo(name) info.date_time = now info.compress_type = zipfile.ZIP_DEFLATED file.writestr(info, name*1000) file.close() # oeffne die Datei erneut, um zu sehen, was drin ist file = zipfile.ZipFile("test.zip", "r") for info in file.infolist(): print info.filename, info.date_time, info.file_size, info.compress_size life (2000, 12, 1, 0, 12, 1) 4000 26 of (2000, 12, 1, 0, 12, 1) 2000 18 brian (2000, 12, 1, 0, 12, 1) 5000 31
Das Modul gzip Das Modul gzip ermBglicht es, mit gzip komprimierte Dateien zu lesen und zu speichern, als ob es gewBhnliche Dateien w;ren. Siehe Beispiel 5-24. Beispiel 5-24: Verwendung des Moduls gzip zum Lesen einer komprimierten Datei File: gzip-example-1.py import gzip file = gzip.GzipFile("samples/sample.gz") print file.read() Well it certainly looks as though we're in for a splendid afternoon's sport in this the 127th Upperclass Twit of the Year Show.
Die Standardimplementierung untersttzt nicht die Methoden seek und tell. Beispiel 5-25 zeigt, wie man die Vorw;rtssuche hinzufgen kann.
157
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 5: Dateiformate Beispiel 5-25: Erweiterung des Moduls gzip zur Unterst6tzung von seek/tell File: gzip-example-2.py import gzip class gzipFile(gzip.GzipFile): # fuegt seek/tell-Unterstuetzung zu GzipFile hinzu offset = 0 def read(self, size=None): data = gzip.GzipFile.read(self, size) self.offset = self.offset + len(data) return data def seek(self, offset, whence=0): # finde neue Position heraus # (wir koennen nur vorwaerts suchen) if whence == 0: position = offset elif whence == 1: position = self.offset + offset else: raise IOError, "Ungueltiges Argument" if position < self.offset: raise IOError, "Kann nicht rueckwaerts suchen" # in 16K-Bloecken vorwaerts springen while position > self.offset: if not self.read(min(position - self.offset, 16384)): break def tell(self): return self.offset # # probiere es aus file = gzipFile("samples/sample.gz") file.seek(80) print file.read() this the 127th Upperclass Twit of the Year Show.
158
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
6 Verarbeitung von Mail- und News-Nachrichten »To be removed from our list of future commercial postings by [SOME] PUBLISHING COMPANY an Annual Charge of Ninety Five dollars is required. Just send $95.00 with your Name, Address and Name of the Newsgroup to be removed from our list.« – Newsgruppen-Werbemll, Juli 1996
1bersicht Python ist reich an Modulen zur Verarbeitung von Mail- und News-Nachrichten sowie einiger verbreiteter Mail-Archivformate (Mailbox).
Das Modul rfc822 Das Modul rfc822 enth;lt einen Parser fr Mail- und News-Nachrichten (sowie alle anderen Nachrichten, die dem RFC 822-Standard gengen, wie beispielsweise HTTPHeader). Im Grunde genommen besteht eine RFC-822-konforme Nachricht aus einer Reihe von Header-Feldern, auf die mindestens eine Leerzeile folgt, sowie dem NachrichtenkBrper selbst. Hier ist beispielsweise eine kurze Mail-Nachricht. Die ersten fnf Zeilen bilden den Nachrichten-Header, und die eigentliche Nachricht (in diesem Falle eine einzelne Zeile) folgt nach einer Leerzeile: Message-Id: <20001114144603.00abb310@oreilly.com> Date: Tue, 14 Nov 2000 14:55:07 -0500 To: "Fredrik Lundh" From: Frank
159
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten Subject: Re: python library book! Where is it?
Beispiel 6-1 zeigt, wie der Nachrichten-Parser die Header einliest und ein Dictionary;hnliches Objekt zurckgibt, mit den Nachrichten-Headern als Schlssel. Beispiel 6-1: Benutzung des rfc822-Moduls File: rfc822-example-1.py import rfc822 file = open("samples/sample.eml") message = rfc822.Message(file) for k, v in message.items(): print k, "=", v print len(file.read()), "Bytes im Nachrichten-Body" subject = Re: python library book! from = "Frank" message-id = <20001114144603.00abb310@oreilly.com> to = "Fredrik Lundh" date = Tue, 14 Nov 2000 14:55:07 -0500 25 Bytes im Nachrichten-Body
Das Nachrichtenobjekt bietet auch eine Reihe bequemer Methoden, die Ihnen das Parsen von Adreßfeldern und Datumsangaben abnehmen, wie man in Beispiel 6-2 sehen kann. Beispiel 6-2: Parsen von Header-Feldern mit dem rfc822-Modul File: rfc822-example-2.py import rfc822 file = open("samples/sample.eml") message = rfc822.Message(file) print message.getdate("date") print message.getaddr("from") print message.getaddrlist("to") (2000, 11, 14, 14, 55, 7, 0, 0, 0) ('Frank', 'your@editor') [('Fredrik Lundh', 'fredrik@effbot.org')]
160
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul mimetools Die Adreßfelder werden in Tupel (Mail, richtiger Name) zerlegt. Das Datumsfeld wird in ein 9-Tupel zerlegt, genau richtig fr die Weiterverarbeitung mit dem time-Modul.
Das Modul mimetools Der Standard Multipurpose Internet Mail Extensions (MIME) definiert, wie man NichtASCII-Text, Bilder und andere Daten in RFC-822-konformen Nachrichten unterbringt. Das Modul mimetools, siehe Beispiel 6-3, enth;lt eine Reihe von Werkzeugen zum Erstellen von Programmen, mit denen man MIME-Nachrichten lesen oder schreiben kann. Unter anderem enth;lt es eine Version der Message-Klasse des rfc822-Moduls, die etwas mehr von MIME-codierten Nachrichten versteht. Beispiel 6-3: Benutzung des Moduls mimetools File: mimetools-example-1.py import mimetools file = open("samples/sample.msg") msg = mimetools.Message(file) print "Typ", "=>", msg.gettype() print "Codierung", "=>", msg.getencoding() print "PListe", "=>", msg.getplist() print "Header", "=>" for k, v in msg.items(): print " ", k, "=", v Typ => text/plain Codierung => 7bit PListe => ['charset="iso-8859-1"'] Header => mime-version = 1.0 content-type = text/plain; charset="iso-8859-1" to = effbot@spam.egg date = Fri, 15 Oct 1999 03:21:15 -0400 content-transfer-encoding = 7bit from = "Fredrik Lundh" subject = By the way... ...
161
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten
Das Modul MimeWriter Das Modul MimeWriter (siehe Beispiel 6-4) kann dazu verwendet werden, um »Multipart«-Nachrichten, wie im MIME-Mail-Standard definiert, zu schreiben. Beispiel 6-4: Benutzung des Moduls MimeWriter File: mimewriter-example-1.py import MimeWriter # Daten-Codierer import quopri import base64 import StringIO import sys TEXT = """ Hier kommt das Bild, um das Sie gebeten haben. Hoffentlich entspricht es Ihren Erwartungen. """ FILE = "samples/sample.jpg" file = sys.stdout # # erzeuge eine MIME Multipart Writer Instanz mime = MimeWriter.MimeWriter(file) mime.addheader("Mime-Version", "1.0") mime.startmultipartbody("mixed") # f`ge eine Text-Nachricht hinzu part = mime.nextpart() part.addheader("Content-Transfer-Encoding", "quoted-printable") part.startbody("text/plain") quopri.encode(StringIO.StringIO(TEXT), file, 0) # f`ge ein Bild hinzu part = mime.nextpart() part.addheader("Content-Transfer-Encoding", "base64") part.startbody("image/jpeg")
162
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul MimeWriter Beispiel 6-4: Benutzung des Moduls MimeWriter (Fortsetzung) base64.encode(open(FILE, "rb"), file) mime.lastpart()
Die Ausgabe sieht in etwa so aus: Content-Type: multipart/mixed; boundary='host.1.-852461.936831373.130.24813' --host.1.-852461.936831373.130.24813 Content-Type: text/plain Context-Transfer-Encoding: quoted-printable Hier kommt das Bild, um das Sie gebeten haben. Hoffentlich entspricht es Ihren Erwartungen. --host.1.-852461.936831373.130.24813 Content-Type: image/jpeg Context-Transfer-Encoding: base64 /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRof HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIy ... 1e5vLrSYbJnEVpEgjCLx5mPU0qsVK0UaxjdNlS+1U6pfzTR8IzEhj2HrVG6m8m18xc8cIKSC tCuFyC746j/Cq2pTia4WztfmKjGBXTCmo6IUpt== --host.1.-852461.936831373.130.24813--
Beispiel 6-5, das etwas grBßer geraten ist, benutzt eine Hilfsklasse, die jeden Unterabschnitt in der passendsten Weise abspeichert. Beispiel 6-5: Eine Hilfsklasse f6r das Modul MimeWriter File: mimewriter-example-2.py import MimeWriter import string, StringIO, sys import re, quopri, base64 # Test, ob der String Nicht-ASCII-Zeichen enth_lt must_quote = re.compile("[\177-\377]").search # # Codierer def encode_quoted_printable(infile, outfile): quopri.encode(infile, outfile, 0) class Writer:
163
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten Beispiel 6-5: Eine Hilfsklasse f6r das Modul MimeWriter (Fortsetzung) def __init__(self, file=None, blurb=None): if file is None: file = sys.stdout self.file = file self.mime = MimeWriter.MimeWriter(file) self.mime.addheader("Mime-Version", "1.0") file = self.mime.startmultipartbody("mixed") if blurb: file.write(blurb) def close(self): "Ende der Nachricht" self.mime.lastpart() self.mime = self.file = None def write(self, data, mimetype="text/plain"): "Schreibe Daten von String oder Datei in Nachricht" # Daten sind entweder eine ge^ffnete Datei oder ein String if type(data) is type(""): file = StringIO.StringIO(data) else: file = data data = None part = self.mime.nextpart() typ, subtyp = string.split(mimetype, "/", 1) if typ == "text": # Text-Daten encoding = "quoted-printable" encoder = lambda i, o: quopri.encode(i, o, 0) if data and not must_quote(data): # Kopieren, nicht codieren encoding = "7bit" encoder = None else: # bin_re Daten (Bild, Sound, Anwendung, ...) encoding = "base64" encoder = base64.encode # # schreibe Header des Nachrichtenteils
164
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul mailbox Beispiel 6-5: Eine Hilfsklasse f6r das Modul MimeWriter (Fortsetzung) if encoding: part.addheader("Content-Transfer-Encoding", encoding) part.startbody(mimetype) # # schreibe Body des Nachrichtenteils if encoder: encoder(file, self.file) elif data: self.file.write(data) else: while 1: data = infile.read(16384) if not data: break outfile.write(data) # # und ausprobieren BLURB = "Wenn Sie das lesen k^nnen, ist Ihr Mailer nicht MIME-f_hig\n" mime = Writer(sys.stdout, BLURB) # Textnachricht hinzuf`gen mime.write("""\ Hier kommt das Bild, um das Sie gebeten haben. Hoffentlich entspricht es Ihren Erwartungen. """, "text/plain") # Bild hinzuf`gen mime.write(open("samples/sample.jpg", "rb"), "image/jpeg") mime.close()
Das Modul mailbox Das Modul mailbox enth;lt Code, der mit einer Vielzahl verschiedener Mailbox-Formate unmgehen kann (haupts;chlich Unix-Formate), wie in Beispiel 6-6 zu sehen. Die meisten Mailbox-Formate speichern einfache, RFC-822-konforme Nachrichten in einer langen Textdatei, wobei eine Art Trennlinie benutzt wird, um die Nachrichten zu separieren.
165
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten Beispiel 6-6: Verwendung des Moduls mailbox File: mailbox-example-1.py import mailbox mb = mailbox.UnixMailbox(open("/var/spool/mail/effbot")) while 1: msg = mb.next() if not msg: break for k, v in msg.items(): print k, "=", v body = msg.fp.read() print len(body), "Bytes im Nachrichten-Body" subject = for he's a ... message-id = <199910150027.CAA03202@spam.egg> received = (from fredrik@pythonware.com) by spam.egg (8.8.7/8.8.5) id CAA03202 for effbot; Fri, 15 Oct 1999 02:27:36 +0200 from = Fredrik Lundh date = Fri, 15 Oct 1999 12:35:36 +0200 to = effbot@spam.egg 1295 Bytes im Nachrichten-Body
Das Modul mailcap Das Modul mailcap in Beispiel 6-7 enth;lt Code, der mit mailcap-Dateien operiert. Diese enthalten Informationen ber die Behandlung unterschiedlicher DokumentenFormate (auf Unix-Plattformen). Beispiel 6-7: Benutzung des Moduls mailcap f6r ein FBhigkeiten-Verzeichnis File: mailcap-example-1.py import mailcap caps = mailcap.getcaps() for k, v in caps.items(): print k, "=", v image/* = [{'view': 'pilview'}] application/postscript = [{'view': 'ghostview'}]
In Beispiel 6-7 benutzt das System pilview fr Bilder aller Art sowie ghostscript fr PostScript-Dokumente. Beispiel 6-8 zeigt, wie man mit Hilfe von mailcap die passenden Programme findet.
166
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul mimetypes Beispiel 6-8: Verwendung des Moduls mailcap zum Auffinden eines geeigneten Programms File: mailcap-example-2.py import mailcap caps = mailcap.getcaps() command, info = mailcap.findmatch( caps, "image/jpeg", "view", "samples/sample.jpg" ) print command pilview samples/sample.jpg
Das Modul mimetypes Das Modul mimetypes untersttzt die Ermittlung des MIME-Typs fr einen gegebenen »Uniform Resource Locator« (URL). Dies basiert auf einer eingebauten Tabelle sowie den Konfigurationsdateien von Apache und Netscape, sofern diese gefunden werden. Dieses Modul wird in Beispiel 6-9 gezeigt. Beispiel 6-9: Benutzung des Moduls mimetypes File: mimetypes-example-1.py import mimetypes import glob, urllib for file in glob.glob("samples/*"): url = urllib.pathname2url(file) print file, mimetypes.guess_type(url) samples\sample.au ('audio/basic', None) samples\sample.ini (None, None) samples\sample.jpg ('image/jpeg', None) samples\sample.msg (None, None) samples\sample.tar ('application/x-tar', None) samples\sample.tgz ('application/x-tar', 'gzip') samples\sample.txt ('text/plain', None) samples\sample.wav ('audio/x-wav', None) samples\sample.zip ('application/zip', None)
Das Modul packmail ($berholt) Das Modul packmail enth;lt Hilfsmittel, um Unix-Shell-Archive zu erzeugen. Wenn Sie die richtigen Werkzeuge installiert haben (auf einer Unix-Maschine sind diese bereits installiert), kBnnen Sie solch ein Archiv einfach entpacken, indem Sie es ausfh167
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten ren. Beispiel 6-10 zeigt, wie man eine einzelne Datei mit Hilfe von packmail einpackt. Beispiel 6-11 zeigt hingegen, wie das Modul einen kompletten Verzeichnisbaum zusammenpacken kann. Beispiel 6-10: Benutzung des Moduls packmail zum Packen einer einzelnen Datei File: packmail-example-1.py import packmail import sys packmail.pack(sys.stdout, "samples/sample.txt", "sample.txt") echo sample.txt sed "s/^X//" >sample.txt <<"!" XWe will perhaps eventually be writing only small Xmodules, which are identified by name as they are Xused to build larger ones, so that devices like Xindentation, rather than delimiters, might become Xfeasible for expressing local structure in the Xsource language. X -- Donald E. Knuth, December 1974 !
Beispiel 6-11: Benutzung des Moduls packmail zum Packen eines kompletten Verzeichnisbaums File: packmail-example-2.py import packmail import sys packmail.packtree(sys.stdout, "samples")
Beachten Sie, daß dieses Modul keine bin;ren Dateien, wie Ger;usch-Schnipsel und Bilder, verarbeiten kann.
Das Modul mimify Das Modul mimify konvertiert Text-Nachrichten im MIME-Format von codierten Formaten in einfachen Text (normalerrweise ISO Latin 1) und zurck. Es kann als ein Kommandozeilen-Werkzeug verwendet werden sowie als Umwandlungsfilter fr bestimmte Mail-Agenten: $ mimify.py -e raw-message mime-message $ mimify.py -d mime-message raw-message
Es kann ebenso als Modul benutzt werden, wie in Beispiel 6-12 gezeigt.
168
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul mimify Beispiel 6-12: Benutzung des Moduls mimify zum Decodieren einer Nachricht File: mimify-example-1.py import mimify import sys mimify.unmimify("samples/sample.msg", sys.stdout, 1)
Hier ist eine MIME-Nachricht mit zwei Teilen, einer als »quoted-printable« codiert und der andere als »base64«. Das dritte Argument von unmimify regelt, ob base64-codierte Teile decodiert werden sollen oder nicht: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary='boundary' this is a multipart sample file. the two parts both contain ISO Latin 1 text, with different encoding techniques. --boundary Content-Type: text/plain Content-Transfer-Encoding: quoted-printable sillmj=F6lke! blindstyre! medisterkorv! --boundary Content-Type: text/plain Content-Transfer-Encoding: base64 a29tIG5lciBiYXJhLCBvbSBkdSB09nJzIQ== --boundary--
Hier ist das decodierte Ergebnis (sehr viel lesbarer, zumindest wenn Sie die Sprache kennen): MIME-Version: 1.0 Content-Type: multipart/mixed; boundary= 'boundary' this is a multipart sample file. the two parts both contain ISO Latin 1 text, with different encoding techniques. --boundary Content-Type: text/plain sillmj^lke! blindstyre! medisterkorv! --boundary Content-Type: text/plain kom ner bara, om du t^rs!
169
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 6: Verarbeitung von Mail- und News-Nachrichten Beispiel 6-13 zeigt, daß das Codieren von Nachrichten ebenso einfach ist. Beispiel 6-13: Verwendung des Moduls mimify zum Codieren einer Nachricht File: mimify-example-2.py import mimify import StringIO, sys # # Decodiere Nachricht in einen Stringpuffer file = StringIO.StringIO() mimify.unmimify("samples/sample.msg", file, 1) # # Codiere Nachricht vom Stringpuffer file.seek(0) # r`ckspulen mimify.mimify(file, sys.stdout)
Das Modul multifile Das Modul multifile ist ein Hilfsmodul, das es Ihnen ermBglicht, jeden Teil einer mehrteiligen MIME-Nachricht als eine eigene Datei anzusprechen, wie in Beispiel 6-14 gezeigt. Beispiel 6-14: Benutzung des Moduls multifile File: multifile-example-1.py import multifile import cgi, rfc822 infile = open("samples/sample.msg") message = rfc822.Message(infile) # Zerlegte Header-Zeilen ausgeben for k, v in message.items(): print k, "=", v # CGI-Hilfsfunktion, um den content-type-Header zu parsen type, params = cgi.parse_header(message["content-type"])
170
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul multifile Beispiel 6-14: Benutzung des Moduls multifile (Fortsetzung) if type[:10] == "multipart/": # Mehrteilige Nachricht boundary = params["boundary"] file = multifile.MultiFile(infile) file.push(boundary) while file.next(): submessage = rfc822.Message(file) # drucke Teilnachricht print "-" * 68 for k, v in submessage.items(): print k, "=", v print print file.read() file.pop() else: # Klartext-Nachricht print infile.read()
171
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
7 Netzwerkprotokolle »Increasingly, people seem to misinterpret complexity as sophistication, which is baffling – the incomprehensible should cause suspicion rather than admiration. Possibly this trend results from a mistaken belief that using a somewhat mysterious device confers an aura of power on the user.« – Niklaus Wirth
1bersicht Dieses Kapitel beschreibt die Python-Untersttzung fr das Socket-Protokoll sowie die Netzwerkmodule, die auf dem Modul socket aufbauen. Diese enthalten Client-Handler fr die popul;rsten Internetprotokolle sowie mehrere Rahmenwerke (Frameworks), die zur Implementierung von Internet-Servern genutzt werden kBnnen. Fr die Beispiele auf unterer Ebene in diesem Kapitel werde ich zwei Protokolle zur Illustration einsetzen: das Internet Time Protocol und das Hypertext Transfer Protocol.
Internet Time Protocol Das Internet Time Protocol (RFC 868, Postel und Harrenstien, 1983) ist ein einfaches Protokoll, das Netzwerk-Clients Zugriff auf die aktuelle Uhrzeit eines Servers ermBglicht. Da dieses Protokoll relativ leichtgewichtig ist, bieten viele (aber beileibe nicht alle) Unix-Systeme es an. Es ist auch fast so einfach zu implementieren, wie ein Netzwerkprotokoll nur sein kann. Der Server wartet einfach auf eine Netzwerkanforderung und liefert augenblicklich die aktuelle Zeit als einen 4-Byte-Integer mit der Anzahl der Sekunden seit dem 1. Januar 1900 zurck. Dieses Protokoll ist in der Tat so simpel, daß ich die komplette Spezifikation hier einfgen kann:
173
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle File: rfc868.txt1 Network Working Group Request for Comments: 868
J. Postel - ISI K. Harrenstien - SRI May 1983 Time Protocol
Dieser RFC spezifiziert einen Standard f`r die ARPA Internet-Gemeinschaft. Rechner auf dem ARPA Internet, die sich entschließen, ein Time Protocol zu implementieren, sollen diesen Standard annehmen und implementieren. Dieses Protokoll bietet eine standortunabh_ngige, maschinenlesbare Angabe von Datum und Uhrzeit. Der Time-Service sendet zur ausl^senden Quelle die Zeit in Sekunden seit dem 1. Januar 1900 zur`ck. Eine Motivation stammt von der Tatsache, daß nicht alle Systeme `ber eine Uhr f`r Datum/Uhrzeit verf`gen, und alle unterliegen gelegentlichen Menschen- oder Maschinenfehlern. Die Benutzung von Time-Servern macht es m^glich, schnell die Vorstellung des Systems `ber die Zeit zu best_tigen oder zu korrigieren, indem man kurz eine Abfrage einer Reihe unabh_ngiger Standorte durchf`hrt. Dieses Protokoll kann entweder auf das Transmission Control Protocol (TCP) oder auf das User Datagram Protocol (UDP) aufsetzen. Wenn via TCP benutzt, funktioniert der Time-Service wie folgt: S: U: S: U: U: S:
Lausche auf Port 37 (45 oktal). Verbinde mit Port 37. Sende die Zeit als eine 32-Bit-Bin_rzahl. Empfange die Zeit. Schließe die Verbindung. Schließe die Verbindung.
Der Server lauscht auf eine Verbindung auf Port 37. Wenn die Verbindung aufgebaut ist, liefert der Server einen 32-Bit-Zeitwert zur`ck und schließt die Verbindung. Wenn der Server nicht in der Lage ist, die Uhrzeit an seinem Standort festzustellen, sollte er entweder die Verbindung verweigern oder sie schließen, ohne etwas zu senden. Wenn `ber UDP benutzt, funktioniert der Time-Service wie folgt: S: U: S: S: U:
Lausche auf Port 37 (45 oktal). Sende ein leeres Datagramm an Port 37. Empfange das leere Datagramm. Sende ein Datagramm mit der Zeit als 32-Bit-Bin_rzahl. Empfange das Zeit-Datagramm.
1 Hier nicht Originaltext, sondern inoffizielle $bersetzung widergegeben – Anm. d. $.
174
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
5bersicht Der Server lauscht auf ein Datagramm auf Port 37. Wenn ein Datagramm eintrifft, liefert der Server ein Datagramm zur`ck, das den 32-BitZeitwert enth_lt. Wenn der Server nicht in der Lage ist, die Uhrzeit an seinem Standort festzustellen, sollte er das ankommende Datagramm verwerfen und keine Erwiderung machen. Die Zeit Die Zeit ist die Anzahl der Sekunden seit 00:00 (Mitternacht) 1. Januar 1900 GMT, so daß die Zeit 1 gerade 00:00:01 ist am 1. Januar 1900 GMT. Diese Basis wird bis zum Jahr 2036 ausreichen. Zum Beispiel: die Zeit 2,208,988,800 2,398,291,200 2,524,521,600 2,629,584,000 und -1,297,728,000
entspricht entspricht entspricht entspricht entspricht
00:00 00:00 00:00 00:00 00:00
1 1 1 1 17
Jan Jan Jan May Nov
1970 1976 1980 1983 1858
GMT, GMT, GMT, GMT, GMT.
Hypertext Transfer Protocol Das Hypertext Transfer Protocol (HTTP, RFC 2616, Fielding u.a.) ist etwas vollkommen anderes. Die aktuellste Spezifikation (Version 1.1) hat ber 100 Seiten. In seiner einfachsten Form ist dieses Protokoll sehr geradlinig. Um ein Dokument zu holen, verbindet sich der Client mit dem Server und sendet eine Anforderung (Request) wie etwa die folgende: GET /hello.txt HTTP/1.0 Host: hostname User-Agent: name [optional request body]
Im Gegenzug gibt der Server eine Antwort (Response) wie diese zurck: HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 7 Hello
Sowohl die Request- als auch die Response-Header enthalten normalerweise mehr Felder, aber das Host-Feld im Request-Header ist das einzige, das grunds;tzlich immer vorhanden sein muß. Die Header-Zeilen werden durch »\r\n« getrennt, und dem Kopfbereich muß eine Leerzeile folgen, selbst wenn gar kein KBrper vorhanden ist (dies gilt fr Request und Response).
175
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Der Rest der HTTP-Spezifikation dreht sich um Sachen wie die Aushandlung des Inhaltstyps, Cache-Vorrichtungen, dauerhafte Verbindungen und vieles mehr. Die komplette Beschreibung finden Sie unter Hypertext Transfer Protocol – HTTP/1.1 (http://www.w3. org/Protocols).
Das Modul socket Das socket-Modul implementiert eine Schnittstelle zur Socket-Kommunikationsschicht. Mit Hilfe dieses Moduls kBnnen Sie sowohl Client- als auch Server-Sockets erstellen. Lassen Sie uns mit einem Client-Beispiel beginnen. Der Client in Beispiel 7-1 nimmt Verbindung zu einem Server fr das Time Protocol auf, liest die 4-Byte-Antwort und konvertiert sie in einen Zeitwert. Beispiel 7-1: Implementierung eines Time-Clients mit dem Modul socket File: socket-example-1.py import socket import struct, time # Server HOST = "www.python.org" PORT = 37 # Referenz-Zeit (in Sekunden seit 1900-01-01 00:00:00) TIME1970 = 2208988800L # 1970-01-01 00:00:00 # verbinde mit Server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) # t t t
lies 4 Bytes und konvertiere in Zeitwert = s.recv(4) = struct.unpack("!I", t)[0] = int(t - TIME1970)
s.close() # Ergebnisse ausgeben print "Serverzeit ist", time.ctime(t) print "lokale Uhr ist", int(time.time()) - t, "Sekunden daneben" Serverzeit ist Sat Oct 09 16:42:36 1999 lokale Uhr ist 8 Sekunden daneben
Die Fabrikfunktion socket erzeugt einen neuen Socket vom angegebenen Typ (in diesem Falle einen Internet Strom-Socket, auch bekannt als TCP-Socket). Die connectMethode versucht, diesen Socket mit dem gegebenen Server zu verbinden. Sobald das geklappt hat, wird die Methode recv verwendet, um Daten zu lesen. 176
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul socket Das Erzeugen eines Server-Socket geht ;hnlich vor sich. Aber anstatt sich an einem Server anzumelden, binden (bind) Sie den Socket an einen Port der lokalen Maschine, teilen ihm mit, er mBchte auf eingehende Anfragen hBren (listen), und verarbeiten jede Anfrage so schnell wie irgend mBglich. Beispiel 7-2 erzeugt einen Time-Server, der an Port 8037 auf der lokalen Maschine gebunden ist (Portnummern bis 1024 sind fr das System reserviert, und Sie mssen Root-Rechte besitzen, um diese zur Implementierung von Diensten auf einem UnixSystem zu verwenden). Beispiel 7-2: Verwendung des Moduls socket zur Implementierung eines Time-Servers File: socket-example-2.py import socket import struct, time # Benutzer-zug_nglicher Port PORT = 8037 # Referenz-Zeit TIME1970 = 2208988800L # Server aufbauen service = socket.socket(socket.AF_INET, socket.SOCK_STREAM) service.bind(("", PORT)) service.listen(1) print "Lausche auf Port", PORT while 1: # Server f`r immer channel, info = service.accept() print "Verbindung von", info t = int(time.time()) + TIME1970 t = struct.pack("!I", t) channel.send(t) # sende Zeitstempel channel.close() # trenne Verbindung Lausche auf Port 8037 Verbindung von ('127.0.0.1', 1469) Verbindung von ('127.0.0.1', 1470) ...
Der Aufruf von listen sagt dem Socket, daß wir bereit sind, eingehende Verbindungen anzunehmen. Das Argument gibt die GrBße der Verbindungswarteschlange an (die Verbindungsanforderungen aufnimmt, fr die unser Programm bisher noch keine Zeit hatte). Schließlich bergibt die accept-Schleife die aktuelle Zeit an jeden Client, der sich zu verbinden traut.
177
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beachten Sie, daß die accept-Funktion ein neues Socket-Objekt zurckgibt, das direkt mit dem Client verbunden ist. Der Original-Socket wird nur benutzt, um die Verbindung herzustellen; jeder weitere Verkehr l;uft ber den neuen Socket. Zum Testen dieses Servers kBnnen wir Beispiel 7-3 benutzen, eine verallgemeinerte Version von Beispiel 7-1. Beispiel 7-3: Ein Client f6r das Time Protocol File: timeclient.py import socket import struct, sys, time # voreingestellter Server host = "localhost" port = 8037 # Referenzzeit (in Sekunden seit 1900-01-01 00:00:00) TIME1970 = 2208988800L # 1970-01-01 00:00:00 def gettime(host, port): # hole Zeitpuffer vom Stream-Server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) t = s.recv(4) s.close() t = struct.unpack("!I", t)[0] return int(t - TIME1970) if __name__ == "__main__": # Kommandozeilen-Werkzeug if sys.argv[1:]: host = sys.argv[1] if sys.argv[2:]: port = int(sys.argv[2]) else: port = 37 # Voreinstellung f`r ^ffentliche Server t = gettime(host, port) print "Serverzeit ist", time.ctime(t) print "lokale Uhr ist", int(time.time()) - t, "Sekunden daneben" Serverzeit ist Sat Oct 09 16:58:50 1999 lokale Uhr ist 0 Sekunden daneben
Das Beispielskript in Beispiel 7-3 kann ebenso als Modul benutzt werden. Um die aktuelle Zeit von einem Server zu bekommen, importieren Sie das Modul timeclient und rufen dann die Funktion gettime auf. Bis hierhin haben wir Strom-(oder TCP-)Sockets benutzt. Die Spezifikation des Time Protocol erw;hnt aber auch UDP-Sockets oder Datagramme. Strom-Sockets funktionie-
178
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul socket ren ziemlich genau wie eine Telefonleitung: Sie werden es mitkriegen, ob jemand am anderen Ende den HBrer abnimmt, und Sie merken auch genau, wenn aufgelegt wird. Im Gegensatz dazu ist das Senden von Datagrammen mehr wie in einen dunklen Raum zu brllen. Jemand kBnnte wohl da sein, aber Sie merken es erst, wenn jemand antwortet. Beispiel 7-4 zeigt, daß Sie sich nicht verbinden mssen, um Daten ber einen Datagramm-Socket zu senden. Statt dessen benutzen Sie die sendto-Methode, die sowohl die Daten als auch die Empf;ngeradresse bernimmt. Zum Lesen eingehender Datagramme benutzen Sie die Methode recvfrom. Beispiel 7-4: Verwendung des Moduls socket zur Implementierung eines Datagramm-Time-Clients File: socket-example-4.py import socket import struct, time # Server HOST = "localhost" PORT = 8037 # Referenz-Zeit (in Sekunden seit 1900-01-01 00:00:00) TIME1970 = 2208988800L # 1970-01-01 00:00:00 # verbinde mit Server s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # sende leeres Paket s.sendto("", (HOST, PORT)) # lies 4 Byte vom Server und konvertiere in Zeitwert t, server = s.recvfrom(4) t = struct.unpack("!I", t)[0] t = int(t - TIME1970) s.close() print "Serverzeit ist", time.ctime(t) print "lokale Uhr ist", int(time.time()) - t, "Sekunden daneben" Serverzeit ist Sat Oct 09 16:42:36 1999 lokale Uhr ist 8 Sekunden daneben
Beachten Sie, daß recvfrom zwei Werte zurckliefert: die tats;chlichen Daten und die Adresse des Absenders. Benutzen Sie letztere, falls Sie antworten mssen. Beispiel 7-5 zeigt den zugehBrigen Server.
179
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-5: Implementierung eines Datagramm-Time-Servers mit dem Modul socket File: socket-example-5.py import socket import struct, time # Benutzer-zug_nglicher Port PORT = 8037 # Referenzzeit TIME1970 = 2208988800L # Server aufbauen service = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) service.bind(("", PORT)) print "Lausche auf Port", PORT while 1: # Server f`r immer data, client = service.recvfrom(0) print "Verbindung von", client t = int(time.time()) + TIME1970 t = struct.pack("!I", t) service.sendto(t, client) # sende Zeitstempel Lausche auf Port 8037 Verbindung von ('127.0.0.1', 1469) Verbindung von ('127.0.0.1', 1470) ...
Der Hauptunterschied ist, daß der Server bind benutzt, um dem Socket eine bekannte Portnummer zuzuweisen, und daß er Daten an die von recvfrom zurckgelieferte Adresse zurckschickt.
Das Modul select Das select-Modul, gezeigt in Beispiel 7-6, ermBglicht es Ihnen, das Eintreffen von Daten auf einem oder mehreren Sockets, Pipes oder anderen kompatiblen Stromobjekten zu prfen. Sie kBnnen einen oder mehrere Sockets an die select-Funktion bergeben, um darauf zu warten, daß sie lesbar oder schreibbar werden oder aber einen Fehler signalisieren:
· 180
Ein Socket wird lesebereit, wenn sich jemand nach einem Aufruf von listen verbindet (was bedeutet, daß accept nicht blockieren wird), wenn Daten vom entfernten Ende ankommen oder wenn der Socket geschlossen oder zurckgesetzt wird (in diesem Falle wrde recv einen leeren String zurckliefern).
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul select
· ·
Ein Socket wird schreibbereit, wenn die Verbindung nach einem nicht-blockierenden Aufruf von connect zustande gekommen ist oder wenn Daten in den Socket geschrieben werden kBnnen. Ein Socket signalisiert eine Fehlerbedingung, wenn die Verbindung nach einem nicht-blockierenden Aufruf von connect scheitert.
Beispiel 7-6: Mit dem Modul select auf 6ber Sockets ankommende Daten warten File: select-example-1.py import select import socket import time PORT = 8037 TIME1970 = 2208988800L service = socket.socket(socket.AF_INET, socket.SOCK_STREAM) service.bind(("", PORT)) service.listen(1) print "Lausche auf Port", PORT while 1: is_readable = [service] is_writable = [] is_error = [] r, w, e = select.select(is_readable, is_writable, is_error, 1.0) if r: channel, info = service.accept() print "Verbindung von", info t = int(time.time()) + TIME1970 t = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255) channel.send(t) # sende Zeitstempel channel.close() # trenne Verbindung else: print "warte weiter" Lausche auf Port 8037 warte weiter warte weiter Verbindung von ('127.0.0.1', 1469) warte weiter Verbindung von ('127.0.0.1', 1470) ...
In Beispiel 7-6 warten wir darauf, daß der hBrende Socket lesebereit wird, was eine eingehende Anforderung anzeigt. Wir behandeln den Kanal-Socket wie gewBhnlich, weil es nicht sehr wahrscheinlich ist, daß das Schreiben der vier Bytes die Netzwerkpuffer
181
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle fluten wird. Wenn Sie grBßere Datenmengen zum Client senden mssen, sollten Sie die Daten der is_writable-Liste am Anfang der Schleife hinzufgen und nur dann schreiben, wenn select Sie dazu auffordert. Wenn Sie den Socket in den nicht-blockierenden Modus versetzen (durch Aufruf der setblocking-Methode), kBnnen Sie select benutzen, um auf eine Verbindung zu warten, aber das Modul asyncore (siehe n;chster Abschnitt) bietet ein m;chtiges Rahmen-
werk, das dies alles fr Sie erledigt, so daß ich hier nicht weiter ins Detail gehen mBchte.
Das Modul asyncore Das Modul asyncore stellt eine »reaktive« Socket-Implementierung zur Verfgung. Statt Socket-Objekte zu erzeugen und Methoden aufzurufen, um etwas zu tun, ermBglicht Ihnen dieses Modul, Code zu schreiben, der ausgefhrt wird, wenn etwas getan werden kann. Um einen asynchronen Socket-Handler zu schreiben, leitet man eine Unterklasse von der Klasse dispatcher ab und berscheibt eine oder mehrere der folgenden Methoden:
· · · · · · ·
handle_connect wird aufgerufen, wenn eine Verbindung erfolgreich aufgebaut
wurde. handle_expt wird aufgerufen, wenn eine Verbindung mißlingt. handle_accept wird aufgerufen, wenn eine Verbindungsanforderung an einen hBrenden Socket gestellt wird. Die Rckruffunktion sollte die accept-Methode benutzen, um den Client-Socket zu bekommen. handle_read wird gerufen wenn zu lesende Daten am Socket vorhanden sind. Der Rckruf sollte die Methode recv rufen um die Daten zu erhalten. handle_write wird aufgerufen, wenn Daten in den Socket geschrieben werden kBnnen. Benutzen Sie die Methode send zum Schreiben von Daten. handle_close wird aufgerufen, wenn der Socket geschlossen oder zurckgesetzt
wird. handle_error(type, value, traceback) wird aufgerufen, wenn ein Python-Fehler
in einem der anderen Rckrufe auftritt. Die Standard-Implementierung gibt einen gekrzten Traceback auf sys.stdout aus.
Beispiel 7-7 zeigt einen Time-Client, ;hnlich dem fr das Modul socket. Beispiel 7-7: Holen der Zeit von einem Time-Server mit dem Modul asyncore File: asyncore-example-1.py import asyncore import socket, time
182
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul asyncore Beispiel 7-7: Holen der Zeit von einem Time-Server mit dem Modul asyncore (Fortsetzung) # Referenzzeit (in Sekunden seit 1900-01-01 00:00:00) TIME1970 = 2208988800L # 1970-01-01 00:00:00 class TimeRequest(asyncore.dispatcher): # Zeit-Abfrager (wie in RFC 868 definiert) def __init__(self, host, port=37): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, port)) def writable(self): return 0 # habe nichts zu schreiben def handle_connect(self): pass # Verbindung gegl`ckt def handle_expt(self): self.close() # Verbindung fehlgeschlagen, herunterfahren def handle_read(self): # bestimme lokale Zeit here = int(time.time()) + TIME1970 # hole und entpacke Serverzeit s = self.recv(4) there = ord(s[3]) + (ord(s[2])<<8) + (ord(s[1])<<16) + (ord(s[0])<<24L) self.adjust_time(int(here - there)) self.handle_close() # wir erwarten keine weiteren Daten def handle_close(self): self.close() def adjust_time(self, delta): # `berschreibe diese Methode print "Zeitdifferenz ist", delta # # ausprobieren request = TimeRequest("www.python.org") asyncore.loop() log: adding channel <TimeRequest at 8cbe90> Zeitdifferenz ist 28 log: closing channel 192:<TimeRequest connected at 8cbe90>
183
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Wenn Sie die Protokollmeldungen nicht wollen, berschreiben Sie die Methode log in Ihrer dispatcher -Unterklasse. Beispiel 7-8 zeigt den entsprechenden Time-Server. Beachten Sie, daß zwei dispatcher Unterklassen verwendet werden, eine fr den hBrenden Socket und eine fr den ClientKanal. Beispiel 7-8: Implementierung eines Time Servers mit dem Modul asyncore File: asyncore-example-2.py import asyncore import socket, time # Referenzzeit TIME1970 = 2208988800L class TimeChannel(asyncore.dispatcher): def handle_write(self): t = int(time.time()) + TIME1970 t = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255) self.send(t) self.close() class TimeServer(asyncore.dispatcher): def __init__(self, port=37): self.port = port self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(("", port)) self.listen(5) print "Lausche auf Port", self.port def handle_accept(self): channel, addr = self.accept() TimeChannel(channel) server = TimeServer(8037) asyncore.loop() log: adding channel <TimeServer at 8cb940> Lausche auf Port 8037 log: adding channel <TimeChannel at 8b2fd0> log: closing channel 52:<TimeChannel connected at 8b2fd0>
Zus;tzlich zum schlichten dispatcher enth;lt dieses Modul auch eine Klasse dispatcher_ with_send. Diese Klasse ermBglicht es Ihnen, grBßere Datenmengen zu senden, ohne die Netzwerk-Transportpuffer zu verstopfen.
184
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul asyncore Das Modul in Beispiel 7-9 definiert eine Klasse AsyncHTTP, die auf der Klasse dispatcher_with_send basiert. Wenn Sie eine Instanz dieser Klasse erzeugen, setzt sie einen HTTP GET-Request ab und sendet die eingehenden Daten an ein Zielobjekt »consumer«. Beispiel 7-9: Ausf6hren von HTTP-Anfragen mit dem Modul asyncore File: SimpleAsyncHTTP.py import import import import
asyncore string, socket StringIO mimetools, urlparse
class AsyncHTTP(asyncore.dispatcher_with_send): # HTTP-Requester def __init__(self, uri, consumer): asyncore.dispatcher_with_send.__init__(self) self.uri = uri self.consumer = consumer # wandle URI in g`ltigen Request scheme, host, path, params, query, fragment = urlparse.urlparse(uri) assert scheme == "http", "unterst`tzt nur HTTP-Anfragen" try: host, port = string.split(host, ":", 1) port = int(port) except (TypeError, ValueError): port = 80 # Default-Port if not path: path = "/" if params: path = path + ";" + params if query: path = path + "?" + query self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host) self.host = host self.port = port self.status = None self.header = None self.data = "" # und los geht's! self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, port))
185
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-9: Ausf6hren von HTTP-Anfragen mit dem Modul asyncore (Fortsetzung) def handle_connect(self): # Verbindung gegl`ckt self.send(self.request) def handle_expt(self): # Verbindung fehlgeschlagen; benachrichtige Verbraucher (Status None) self.close() try: http_header = self.consumer.http_header except AttributeError: pass else: http_header(self) def handle_read(self): data = self.recv(2048) if not self.header: self.data = self.data + data try: i = string.index(self.data, "\r\n\r\n") except ValueError: return # fortsetzen else: # parse Header fp = StringIO.StringIO(self.data[:i+4]) # Statuszeile ist "HTTP/version status message" status = fp.readline() self.status = string.split(status, " ", 2) # gefolgt von einem Nachrichten-Header im rfc822-Stil self.header = mimetools.Message(fp) # gefolgt von einem Zeilenwechsel und ggf. der Nutzlast data = self.data[i+4:] self.data = "" # benachrichtige Verbraucher (Status ist nicht Null) try: http_header = self.consumer.http_header except AttributeError: pass else: http_header(self) if not self.connected: return # Kanal wurde durch den Verbraucher geschlossen self.consumer.feed(data) def handle_close(self): self.consumer.close() self.close()
Beispiel 7-10 zeigt ein einfaches Skript, das diese Klasse benutzt.
186
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul asyncore Beispiel 7-10: Verwendung der Klasse SimpleAsyncHTTP File: asyncore-example-3.py import SimpleAsyncHTTP import asyncore class DummyConsumer: size = 0 def http_header(self, request): # verarbeite Header if request.status is None: print "Verbindung fehlgeschlagen" else: print "Status", "=>", request.status for key, value in request.header.items(): print key, "=", value def feed(self, data): # verarbeite eingehende Daten self.size = self.size + len(data) def close(self): # Ende der Daten print self.size, "Bytes im Body" # # ausprobieren consumer = DummyConsumer() request = SimpleAsyncHTTP.AsyncHTTP( "http://www.pythonware.com", consumer ) asyncore.loop() log: adding channel Status => ['HTTP/1.1', '200', 'OK\015\012'] server = Apache/Unix (Unix) content-type = text/html content-length = 3730 ... 3730 Bytes im Body log: closing channel 156:
Beachten Sie, daß das Verbraucher-Interface kompatibel zu den htmllib- und xmllibParsern entworfen wurde, so daß man HTML- oder XML-Daten so ganz nebenbei parsen kann. Beachten Sie weiter, daß die Methode http_header optional ist. Wenn sie nicht definiert ist, wird sie einfach ignoriert.
187
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Ein Problem bei Beispiel 7-10 ist, daß es nicht mit umgeleiteten Ressourcen funktioniert. Beispiel 7-11 fgt eine zus;tzliche Verbraucher-Schicht hinzu, die die Umleitung bernimmt. Beispiel 7-11: Benutzung der Klasse SimpleAsyncHTTP mit Umleitung File: asyncore-example-4.py import SimpleAsyncHTTP import asyncore class DummyConsumer: size = 0 def http_header(self, request): # verarbeite Header if request.status is None: print "Verbindung fehlgeschlagen" else: print "Status", "=>", request.status for key, value in request.header.items(): print key, "=", value def feed(self, data): # verarbeite ankommende Daten self.size = self.size + len(data) def close(self): # Ende der Daten print self.size, "Bytes im Body" class RedirectingConsumer: def __init__(self, consumer): self.consumer = consumer def http_header(self, request): # verarbeite Header if request.status is None or\ request.status[1] not in ("301", "302"): try: http_header = self.consumer.http_header except AttributeError: pass else: return http_header(request) else: # Umleitung! uri = request.header["location"] print "wird umgeleitet nach", uri, "..." request.close() SimpleAsyncHTTP.AsyncHTTP(uri, self)
188
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul asynchat Beispiel 7-11: Benutzung der Klasse SimpleAsyncHTTP mit Umleitung (Fortsetzung) def feed(self, data): self.consumer.feed(data) def close(self): self.consumer.close() # # ausprobieren consumer = RedirectingConsumer(DummyConsumer()) request = SimpleAsyncHTTP.AsyncHTTP( "http://www.pythonware.com/library", consumer ) asyncore.loop() log: adding channel wird umgeleitet nach http://www.pythonware.com/library/ ... log: closing channel 48: log: adding channel Status => ['HTTP/1.1', '200', 'OK\015\012'] server = Apache/Unix (Unix) content-type = text/html content-length = 387 ... 387 Bytes im Body log: closing channel 236:
Wenn der Server den Status 301 (permanente Umleitung) oder 302 (zeitweise Umleitung) zurckgibt, schließt der umleitende Verbraucher die aktuelle Anforderung und setzt eine neue mit der neuen Adresse ab. Alle anderen Aufrufe des Verbrauchers werden an den originalen Verbraucher delegiert.
Das Modul asynchat Das Modul asynchat ist eine Erweiterung zu asyncore. Es bietet zus;tzliche Untersttzung fr zeilenorientierte Protokolle. Weiterhin besitzt es eine verbesserte Hilfe bei der Pufferung ber die Methode push sowie den Erzeuger-Mechanismus. Beispiel 7-12 implementiert einen ;ußerst minimalen HTTP-Responder. Es liefert einfach ein HTML-Dokument zurck, das Informationen von einem HTTP-Request enth;lt (die Ausgabe erscheint im Browser-Fenster).
189
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-12: Implementierung eines minimalen HTTP-Servers mit dem Modul asynchat File: asynchat-example-1.py import asyncore, asynchat import os, socket, string PORT = 8000 class HTTPChannel(asynchat.async_chat): def __init__(self, server, sock, addr): asynchat.async_chat.__init__(self, sock) self.set_terminator("\r\n") self.request = None self.data = "" self.shutdown = 0 def collect_incoming_data(self, data): self.data = self.data + data def found_terminator(self): if not self.request: # Habe Request-Zeile erhalten self.request = string.split(self.data, None, 2) if len(self.request) != 3: self.shutdown = 1 else: self.push("HTTP/1.0 200 OK\r\n") self.push("Content-type: text/html\r\n") self.push("\r\n") self.data = self.data + "\r\n" self.set_terminator("\r\n\r\n") # suche Ende der Header else: # gebe Ladung zur`ck. self.push("<pre>\r\n") self.push(self.data) self.push("\r\n") self.close_when_done() class HTTPServer(asyncore.dispatcher): def __init__(self, port): self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(("", port)) self.listen(5) def handle_accept(self): conn, addr = self.accept() HTTPChannel(self, conn, addr) # # ausprobieren
190
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul asynchat Beispiel 7-12: Implementierung eines minimalen HTTP-Servers mit dem Modul asynchat (Fortsetzung) s = HTTPServer(PORT) print "Service an Port", PORT, "..." asyncore.loop() GET / HTTP/1.1 Accept: */* Accept-Language: en, sv Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; Bruce/1.0) Host: localhost:8000 Connection: Keep-Alive
Das Erzeuger-Interface ermBglicht Ihnen, Objekte mit »push« zu verzBgern, wenn sie zu groß fr den Hauptspeicher sind. asyncore ruft die Methode more des Erzeugers auf, sobald es neue Daten benBtigt. Um das Ende einer Datei zu signalisieren, geben Sie einfach einen Leerstring zurck. Beispiel 7-13 implementiert einen sehr einfachen dateibasierten HTTP-Server ber eine schlichte FileProducer-Klasse, die Daten aus einer Datei liest, immer nur ein paar Kilobyte zur Zeit. Beispiel 7-13: Implementierung eines einfachen HTTP-Servers mit dem Modul asynchat File: asynchat-example-2.py import asyncore, asynchat import os, socket, string, sys import StringIO, mimetools ROOT = "." PORT = 8000 class HTTPChannel(asynchat.async_chat): def __init__(self, server, sock, addr): asynchat.async_chat.__init__(self, sock) self.server = server self.set_terminator("\r\n\r\n") self.header = None self.data = "" self.shutdown = 0 def collect_incoming_data(self, data): self.data = self.data + data if len(self.data) > 16384: # begrenze die Header-Gr^ße, um Angriffen vorzubeugen self.shutdown = 1
191
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-13: Implementierung eines einfachen HTTP-Servers mit dem Modul asynchat (Fortsetzung) def found_terminator(self): if not self.header: # parse HTTP-Header fp = StringIO.StringIO(self.data) request = string.split(fp.readline(), None, 2) if len(request) != 3: # falsch formatierter Request - einfach abbrechen self.shutdown = 1 else: # parse Nachrichten-Header self.header = mimetools.Message(fp) self.set_terminator("\r\n") self.server.handle_request( self, request[0], request[1], self.header ) self.close_when_done() self.data = "" else: pass # ignoriere Body-Daten f`rs erste def pushstatus(self, status, explanation="OK"): self.push("HTTP/1.0 %d %s\r\n" % (status, explanation))
class FileProducer: # ein Erzeuger, der Daten von einem Dateiobjekt liest def __init__(self, file): self.file = file def more(self): if self.file: data = self.file.read(2048) if data: return data self.file = None return ""
class HTTPServer(asyncore.dispatcher): def __init__(self, port=None, request=None): if not port: port = 80 self.port = port if request: self.handle_request = request # externer Anfragen-Handler self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(("", port)) self.listen(5)
192
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul urllib Beispiel 7-13: Implementierung eines einfachen HTTP-Servers mit dem Modul asynchat (Fortsetzung) def handle_accept(self): conn, addr = self.accept() HTTPChannel(self, conn, addr) def handle_request(self, channel, method, path, header): try: # das ist nicht sicher! while path[:1] == "/": path = path[1:] filename = os.path.join(ROOT, path) print path, "=>", filename file = open(filename, "r") except IOError: channel.pushstatus(404, "Not found") channel.push("Content-type: text/html\r\n") channel.push("\r\n") channel.push("Datei nicht gefunden.\r\n") else: channel.pushstatus(200, "OK") channel.push("Content-type: text/html\r\n") channel.push("\r\n") channel.push_with_producer(FileProducer(file)) # # ausprobieren s = HTTPServer(PORT) print "Service an Port", PORT asyncore.loop() Service an Port 8000 log: adding channel log: adding channel samples/sample.htm => .\samples/sample.htm log: closing channel 96:
Das Modul urllib Das Modul urlib besitzt eine vereinheitlichte Client-Schnittstelle fr HTTP, FTP und gopher. Es sucht automatisch den richtigen Protokoll-Handler heraus, basierend auf der Uniform Resource Locator (URL), dir der Bibliothek bergeben wurde. Daten von einer URL zu holen ist extrem einfach. Zun;chst rufen Sie die Methode urlopen auf, und dann lesen Sie einfach von dem zurckgegebenen Strom-Objekt, wie in Beispiel 7-14 gezeigt.
193
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-14: Holen einer entfernten Ressource mit dem Modul urllib File: urllib-example-1.py import urllib fp = urllib.urlopen("http://www.python.org") op = open("out.html", "wb") n = 0 while 1: s = fp.read(8192) if not s: break op.write(s) n = n + len(s) fp.close() op.close() for k, v in fp.headers.items(): print k, "=", v print "es wurden", n, "Bytes kopiert von", fp.url server = Apache/1.3.6 (Unix) content-type = text/html accept-ranges = bytes date = Mon, 11 Oct 1999 20:11:40 GMT connection = close etag = "741e9-7870-37f356bf" content-length = 30832 last-modified = Thu, 30 Sep 1999 12:25:35 GMT es wurden 30832 Bytes kopiert von http://www.python.org
Beachten Sie, daß das Strom-Objekt einige besondere Attribute bereitstellt. headers ist ein Message-Objekt (wie durch das Modul mimetools definiert), und url enth;lt die aktuelle URL. Letztere wird aktualisiert, wenn der Server den Client zu einer neuen URL umleitet. Die Funktion urlopen ist eigentlich eine Hilfsfunktion, die eine Instanz der Klasse FancyURLopener erzeugt und ihre open-Methode aufruft. Um besonderes Verhalten zu erreichen, kBnnen Sie von dieser Klasse ableiten. Beispielsweise loggt sich die Klasse in Beispiel 7-15 automatisch beim Server ein, wenn nBtig.
194
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul urlparse Beispiel 7-15: Verwendung des Moduls urllib mit automatischer Authentifizierung File: urllib-example-3.py import urllib class myURLOpener(urllib.FancyURLopener): # lies eine URL mit automatischer HTTP-Authentifizierung def setpasswd(self, user, passwd): self.__user = user self.__passwd = passwd def prompt_user_passwd(self, host, realm): return self.__user, self.__passwd urlopener = myURLOpener() urlopener.setpasswd("mulder", "trustno1") fp = urlopener.open("http://www.secretlabs.com") print fp.read()
Das Modul urlparse Das Modul urlparse enth;lt Funktionen zur Verarbeitung von URLs sowie zur Konvertierung zwischen URLs und plattformspezifischen Dateinamen, wie in Beispiel 7-16 gezeigt. Beispiel 7-16: Verwendung des Moduls urlparse File: urlparse-example-1.py import urlparse print urlparse.urlparse("http://host/path;params?query#fragment") ('http', 'host', '/path', 'params', 'query', 'fragment')
Eine verbreitete Anwendung ist das Aufteilen einer HTTP-URL in die Rechnername- und Pfad-Komponenten (bei einem HTTP-Request wird der Rechner gebeten, die durch den Pfad identifizierten Daten zurckzuschicken), wie in Beispiel 7-17 gezeigt. Beispiel 7-17: Benutzung des Moduls urlparse zum Parsen von URLs File: urlparse-example-2.py import urlparse scheme, host, path, params, query, fragment =\ urlparse.urlparse("http://host/path;params?query#fragment")
195
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-17: Benutzung des Moduls urlparse zum Parsen von URLs (Fortsetzung) if scheme == "http": print "host", "=>", host if params: path = path + ";" + params if query: path = path + "?" + query print "path", "=>", path host => host path => /path;params?query
Alternativ zeigt Ihnen Beispiel 7-18, wie man die Funktion urlunparse benutzen kann, um eine URL wieder zusammenzufgen. Beispiel 7-18: Benutzung des Moduls urlparse zum Parsen von URLs File: urlparse-example-3.py import urlparse scheme, host, path, params, query, fragment =\ urlparse.urlparse("http://host/path;params?query#fragment") if scheme == "http": print "host", "=>", host print "path", "=>", urlparse.urlunparse( (None, None, path, params, query, None) ) host => host path => /path;params?query
Beispiel 7-19 benutzt die Funktion urljoin, um eine absolute URL mit einer zweiten, mBglicherweise relativen URL zu kombinieren. Beispiel 7-19: Benutzung des Moduls urlparse zum Kombinieren relativer URLs File: urlparse-example-4.py import urlparse base = "http://spam.egg/my/little/pony" for path in "/index", "goldfish", "../black/cat": print path, "=>", urlparse.urljoin(base, path) /index => http://spam.egg/index goldfish => http://spam.egg/my/little/goldfish ../black/cat => http://spam.egg/my/black/cat
196
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul cookie
Das Modul cookie (Neu in 2.0) Dieses Modul bietet grundlegende Cookie-Untersttzung fr HTTP-Clients und -Server. Beispiel 7-20 zeigt seine Anwendung. Beispiel 7-20: Benutzung des Moduls cookie File: cookie-example-1.py import Cookie import os, time cookie = Cookie.SimpleCookie() cookie["user"] = "Mimi" cookie["timestamp"] = time.time() print cookie # simuliere CGI-Rundreise os.environ["HTTP_COOKIE"] = str(cookie) print cookie = Cookie.SmartCookie() cookie.load(os.environ["HTTP_COOKIE"]) for key, item in cookie.items(): # Dictionary-Elemente sind "Morsel"-Instanzen # Benutze value-Attribut, um den aktuellen Wert zu erhalten print key, repr(item.value) Set-Cookie: timestamp=736513200; Set-Cookie: user=Mimi; user 'Mimi' timestamp '736513200'
Das Modul robotparser (Neu in 2.0) Das Modul robotparser liest robots.txt-Dateien, die zur Implementierung des Robot Exclusion Protocol eingesetzt werden (siehe http://info.webcrawler.com/ mak/projects/robots/robots.html). Wenn Sie einen HTTP-Roboter implementieren, der alle mBglichen Websites besuchen soll (nicht nur Ihre eigenen), dann ist es eine gute Idee, mit diesem Modul zu prfen, ob Sie wirklich willkommen sind. Beispiel 7-21 zeigt das Modul robotparser.
197
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-21: Verwendung des Moduls robotparser File: robotparser-example-1.py import robotparser r = robotparser.RobotFileParser() r.set_url("http://www.python.org/robots.txt") r.read() if r.can_fetch("*", "/index.html"): print "darf Homepage holen" if r.can_fetch("*", "/tim_one/index.html"): print "darf das Tim Peters-Archiv holen" darf Homepage holen
Das Modul ftplib Das Modul ftplib enth;lt die Implementierung eines File Transfer Protocol (FTP) Clients. Beispiel 7-22 zeigt, wie man sich einloggt und eine Verzeichnis-Auflistung des LoginVerzeichnisses erh;lt. Beachten Sie, daß das Format der Verzeichnis-Auflistung serverabh;ngig ist (es ist meist das gleiche Format, das auch das Verzeichnis-Anzeigehilfsmittel der Server-Plattform benutzt). Beispiel 7-22: Anzeigen eines Verzeichnisses mit dem Modul ftplib File: ftplib-example-1.py import ftplib ftp = ftplib.FTP("www.python.org") ftp.login("anonymous", "ftplib-example-1") print ftp.dir() ftp.quit() total 34 drwxrwxr-x 11 root drwxrwxr-x 11 root drwxrwxr-x 2 root lrwxrwxrwx 1 root drwxr-xr-x 3 root drwxr-sr-x 3 root drwxrwxr-- 2 root drwxr-xr-x 3 root ...
198
4127 4127 4127 bin wheel 1400 4127 wheel
512 512 512 11 512 512 512 512
Sep Sep Sep Jun May Jun Feb May
14 14 13 29 19 9 8 19
14:18 14:18 15:18 14:34 1998 1997 1998 1998
. .. RCS README -> welcome.msg bin dev dup etc
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul ftplib Das Herunterladen von Dateien ist einfach: Nehmen Sie einfach die entsprechende retr-Funktion. Beachten Sie, daß Sie beim Herunterladen von Textdateien die Zeilenenden selbst hinzufgen mssen. Die Funktion in Beispiel 7-23 benutzt einen lambdaAusdruck, um das auf die Schnelle zu erledigen. Beispiel 7-23: Abrufen von Dateien mit dem Modul ftplib File: ftplib-example-2.py import ftplib import sys def gettext(ftp, filename, outfile=None): # hole eine Textdatei if outfile is None: outfile = sys.stdout # benutze ein Lambda, um vom Server gelesenen Zeilen Newlines anzuf`gen ftp.retrlines("RETR " + filename, lambda s, w=outfile.write: w(s+"\n")) def getbinary(ftp, filename, outfile=None): # hole eine Bin_rdatei if outfile is None: outfile = sys.stdout ftp.retrbinary("RETR " + filename, outfile.write) ftp = ftplib.FTP("www.python.org") ftp.login("anonymous", "ftplib-example-2") gettext(ftp, "README") getbinary(ftp, "welcome.msg") WELCOME to python.org, the Python programming language home site. You are number %N of %M allowed users. Ni! Python Web site: http://www.python.org/ CONFUSED FTP CLIENT? Try begining your login password with '-' dash. This turns off continuation messages that may be confusing your client. ...
Zu guter Letzt ist Beispiel 7-24 ein einfaches Beispiel zum Kopieren von Dateien auf den FTP-Server. Dieses Skript benutzt die Dateierweiterung, um herauszufinden, ob die Datei eine Textdatei oder bin;r ist. Beispiel 7-24: Speichern von Dateien mit dem Modul ftplib File: ftplib-example-3.py import ftplib import os
199
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-24: Speichern von Dateien mit dem Modul ftplib (Fortsetzung) def upload(ftp, file): ext = os.path.splitext(file)[1] if ext in (".txt", ".htm", ".html"): ftp.storlines("STOR " + file, open(file)) else: ftp.storbinary("STOR " + file, open(file, "rb"), 1024) ftp = ftplib.FTP("ftp.fbi.gov") ftp.login("mulder", "trustno1") upload(ftp, "trixie.zip") upload(ftp, "file.txt") upload(ftp, "sightings.jpg")
Das Modul gopherlib Das Modul gopherlib enth;lt die Implementierung eines Gopher-Clients, zu sehen in Beispiel 7-25. Beispiel 7-25: Verwendung des Moduls gopherlib File: gopherlib-example-1.py import gopherlib host = "gopher.spam.egg" f = gopherlib.send_selector("1/", host) for item in gopherlib.get_directory(f): print item ['0', "About Spam.Egg's Gopher Server", "0/About's Spam.Egg's Gopher Server", 'gopher.spam.egg', '70', '+'] ['1', 'About Spam.Egg', '1/Spam.Egg', 'gopher.spam.egg', '70', '+'] ['1', 'Misc', '1/Misc', 'gopher.spam.egg', '70', '+'] ...
Das Modul httplib Das Modul httplib, zu sehen in Beispiel 7-26, stellt eine HTTP-Client-Schnittstelle zur Verfgung. Beispiel 7-26: Benutzung des Moduls httplib File: httplib-example-1.py import httplib
200
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul httplib Beispiel 7-26: Benutzung des Moduls httplib (Fortsetzung) USER_AGENT = "httplib-example-1.py" class Error: # zeigt einen HTTP-Fehler an def __init__(self, url, errcode, errmsg, headers): self.url = url self.errcode = errcode self.errmsg = errmsg self.headers = headers def __repr__(self): return ( "" % (self.url, self.errcode, self.errmsg) ) class Server: def __init__(self, host): self.host = host def fetch(self, path): http = httplib.HTTP(self.host) # schreibe Header http.putrequest("GET", path) http.putheader("User-Agent", USER_AGENT) http.putheader("Host", self.host) http.putheader("Accept", "*/*") http.endheaders() # hole Antwort errcode, errmsg, headers = http.getreply() if errcode != 200: raise Error(errcode, errmsg, headers) file = http.getfile() return file.read() if __name__ == "__main__": server = Server("www.pythonware.com") print server.fetch("/index.htm")
Beachten Sie, daß der von httplib bereitgestellte HTTP-Client blockiert, solange er auf die Antwort des Servers wartet. Eine asynchrone LBsung, die Ihnen unter anderem ermBglicht, mehrere Requests parallel abzuschicken, kBnnen Sie den Beispielen fr das Modul asyncore entnehmen.
201
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle
Daten an einen HTTP-Server senden Das Modul httplib ermBglicht Ihnen aber auch, andere HTTP-Befehle abzusetzen, wie etwa POST in Beispiel 7-27. Beispiel 7-27: Senden von Daten mit dem Modul httplib File: httplib-example-2.py import httplib USER_AGENT = "httplib-example-2.py" def post(host, path, data, type=None): http = httplib.HTTP(host) # schreibe Header http.putrequest("PUT", path) http.putheader("User-Agent", USER_AGENT) http.putheader("Host", host) if type: http.putheader("Content-Type", type) http.putheader("Content-Length", str(len(size))) http.endheaders() # schreibe Body http.send(data) # hole Antwort errcode, errmsg, headers = http.getreply() if errcode != 200: raise Error(errcode, errmsg, headers) file = http.getfile() return file.read() if __name__ == "__main__": post("www.spam.egg", "/bacon.htm", "ein Happen Daten", "text/plain")
Das Modul poplib Das Modul poplib (zu sehen in Beispiel 7-28) enth;lt die Implementierung eines Post Office Protocol (POP3) Clients. Dieses Protokoll wird benutzt, um Nachrichten von einem zentralen Mailserver auf Ihren lokalen Rechner zu verschieben (»pop«).
202
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul poplib Beispiel 7-28: Benutzung des Moduls poplib File: poplib-example-1.py import poplib import string, random import StringIO, rfc822 SERVER = "pop.spam.egg" USER = "mulder" PASSWORD = "trustno1" # mit Server verbinden server = poplib.POP3(SERVER) # einloggen server.user(USER) server.pass_(PASSWORD) # Elemente auf Server auflisten resp, items, octets = server.list() # zuf_llige Nachricht herunterladen id, size = string.split(random.choice(items)) resp, text, octets = server.retr(id) text = string.join(text, "\n") file = StringIO.StringIO(text) message = rfc822.Message(file) for k, v in message.items(): print k, "=", v print message.fp.read() subject = ANN: (the eff-bot guide to) The Standard Python Library message-id = <199910120808.KAA09206@spam.egg> received = (from fredrik@spam.egg) by spam.egg (8.8.7/8.8.5) id KAA09206 for mulder; Tue, 12 Oct 1999 10:08:47 +0200 from = Fredrik Lundh date = Tue, 12 Oct 1999 10:08:47 +0200 to = mulder@spam.egg ...
203
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle
Das Modul imaplib Das Modul imaplib, vorgefhrt in Beispiel 7-29, bietet die Implementierung eines Internet Message Access Protocol-(IMAP-)Clients. Mit diesem Protokoll kBnnen Sie auf Mailordner, die auf einem zentralen Mailserver liegen, so zugreifen, als w;ren sie lokal. Beispiel 7-29: Benutzung des Moduls imaplib File: imaplib-example-1.py import imaplib import string, random import StringIO, rfc822 SERVER = "imap.spam.egg" USER = "mulder" PASSWORD = "trustno1" # mit Server verbinden server = imaplib.IMAP4(SERVER) # einloggen server.login(USER, PASSWORD) server.select() # Elemente auf Server auflisten resp, items = server.search(None, "ALL") items = string.split(items[0]) # zuf_lliges Element holen id = random.choice(items) resp, data = server.fetch(id, "(RFC822)") text = data[0][1] file = StringIO.StringIO(text) message = rfc822.Message(file) for k, v in message.items(): print k, "=", v print message.fp.read() server.logout() subject = ANN: (the eff-bot guide to) The Standard Python Library message-id = <199910120816.KAA12177@larch.spam.egg> to = mulder@spam.egg date = Tue, 12 Oct 1999 10:16:19 +0200 (MET DST) from = <effbot@spam.egg> received = (effbot@spam.egg) by imap.algonet.se (8.8.8+Sun/8.6.12)
204
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul smtplib Beispiel 7-29: Benutzung des Moduls imaplib (Fortsetzung) id KAA12177 for effbot@spam.egg; Tue, 12 Oct 1999 10:16:19 +0200 (MET DST) body text fer test 5
Das Modul smtplib Das Modul smtplib (in Beispiel 7-30 gezeigt) implementiert einen Client fr das Simple Mail Transfer Protocol (SMTP). Dieses Protokoll wird benutzt, um Mail ber Unix-Mailserver zu versenden. Zum Lesen von Mail benutzen Sie bitte die Module poplib oder imaplib. Beispiel 7-30: Benutzung des Moduls smtplib File: smtplib-example-1.py import smtplib import string, sys HOST = "localhost" FROM = "effbot@spam.egg" TO = "fredrik@spam.egg" SUBJECT = "Zu Ihrer Information!" BODY = "N_chste Woche: wie man einen Otter schleudert" body = string.join(( "From: %s" % FROM, "To: %s" % TO, "Subject: %s" % SUBJECT, "", BODY), "\r\n") print body server = smtplib.SMTP(HOST) server.sendmail(FROM, [TO], body) server.quit() From: effbot@spam.egg To: fredrik@spam.egg Subject: Zu Ihrer Information! NWchste Woche: wie man einen Otter schleudert
205
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle
Das Modul telnetlib Das Modul telnetlib bietet eine Implementierung eines Telnet-Clients. Beispiel 7-31 verbindet sich mit einem Unix-Rechner, loggt sich ein und holt dann eine Verzeichnisauflistung ab. Beispiel 7-31: Einloggen in einen entfernten Server mit dem Modul telnetlib File: telnetlib-example-1.py import telnetlib import sys HOST = "spam.egg" USER = "mulder" PASSWORD = "trustno1" telnet = telnetlib.Telnet(HOST) telnet.read_until("login: ") telnet.write(USER + "\n") telnet.read_until("Password: ") telnet.write(PASSWORD + "\n") telnet.write("ls bibliotheksbuch\n") telnet.write("exit\n") print telnet.read_all() [spam.egg mulder]$ ls README SimpleAsyncHTTP.py aifc-example-1.py anydbm-example-1.py array-example-1.py ...
os-path-isabs-example-1.py os-path-isdir-example-1.py os-path-isfile-example-1.py os-path-islink-example-1.py os-path-ismount-example-1.py
Das Modul nntplib Das Modul nntplib stellt eine Implementierung eines Network News Transfer Protocol (NNTP) Clients zur Verfgung.
206
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul nntplib
Auflisten von Nachrichten Bevor Sie Nachrichten von einem Newsserver lesen kBnnen, mssen Sie sich mit dem Server verbinden und dann eine Newsgruppe ausw;hlen. Das Skript in Beispiel 7-32 l;dt obendrein eine komplette Liste von allen Nachrichten auf dem Server herunter und entfernt mehr oder weniger interessante Statistiken aus dieser Liste. Beispiel 7-32: Auflisten von Nachrichten mit dem Modul nntplib File: nntplib-example-1.py import nntplib import string SERVER = "news.spam.egg" GROUP = "comp.lang.python" AUTHOR = "fredrik@pythonware.com" # eff-bots menschlicher Deckname # mit dem Server verbinden server = nntplib.NNTP(SERVER) # eine Newsgruppe w_hlen resp, count, first, last, name = server.group(GROUP) print "Anzahl", "=>", count print "Bereich", "=>", first, last # alle Elemente auf dem Server auflisten resp, items = server.xover(first, last) # etwas Statistik extrahieren authors = {} subjects = {} for id, subject, author, date, message_id, references, size, lines in items: authors[author] = None if subject[:4] == "Re: ": subject = subject[4:] subjects[subject] = None if string.find(author, AUTHOR) >= 0: print id, subject print "Autoren", "=>", len(authors) print "Subjects", "=>", len(subjects) Anzahl => 607 Bereich => 57179 57971 57474 Three decades of Python! ... 57477 More Python books coming... Autoren => 257 Subjects => 200
207
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle
Herunterladen von Nachrichten Eine Nachricht herunterzuladen ist einfach. Rufen Sie nur die Methode article auf, wie in Beispiel 7-33 verdeutlicht wird. Beispiel 7-33: Herunterladen von Nachrichten mit dem Modul nntplib File: nntplib-example-2.py import nntplib import string SERVER = "news.spam.egg" GROUP = "comp.lang.python" KEYWORD = "tkinter" # mit Server verbinden server = nntplib.NNTP(SERVER) resp, count, first, last, name = server.group(GROUP) resp, items = server.xover(first, last) for id, subject, author, date, message_id, references, size, lines in items: if string.find(string.lower(subject), KEYWORD) >= 0: resp, id, message_id, text = server.article(id) print author print subject print len(text), "Zeilen im Artikel" "Fredrik Lundh" Re: Programming Tkinter (In Python) 110 Zeilen im Artikel ...
Beispiel 7-34 zeigt, wie Sie die Nachrichten noch weiter bearbeiten kBnnen, indem Sie sie in ein Message-Objekt einhllen (mit dem rfc822-Modul). Beispiel 7-34: Verarbeitung von Nachrichten mit den Modulen nntplib und rfc822 File: nntplib-example-3.py import nntplib import string, random import StringIO, rfc822 SERVER = "news.spam.egg" GROUP = "comp.lang.python" # mit dem Server verbinden server = nntplib.NNTP(SERVER) resp, count, first, last, name = server.group(GROUP) for i in range(10):
208
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul SocketServer Beispiel 7-34: Verarbeitung von Nachrichten mit den Modulen nntplib und rfc822 (Fortsetzung) try: id = random.randint(int(first), int(last)) resp, id, message_id, text = server.article(str(id)) except (nntplib.error_temp, nntplib.error_perm): pass # keine solche Nachricht (wurde vielleicht gel^scht?) else: break # eine Nachricht gefunden! else: raise SystemExit text = string.join(text, "\n") file = StringIO.StringIO(text) message = rfc822.Message(file) for k, v in message.items(): print k, "=", v print message.fp.read() mime-version = 1.0 content-type = text/plain; charset="iso-8859-1" message-id = <008501bf1417$1cf90b70$f29b12c2@sausage.spam.egg> lines = 22 ... from = "Fredrik Lundh" nntp-posting-host = parrot.python.org subject = ANN: (the eff-bot guide to) The Standard Python Library ...
Wenn Sie erst einmal so weit gekommen sind, kBnnen Sie Module wie htmllib, uu und base64 zur weiteren Verarbeitung der Nachrichten verwenden.
Das Modul SocketServer Das Modul SocketServer bietet ein Rahmenwerk fr Socket-Server verschiedenster Art. Das Modul besitzt mehrere Klassen, die zu Servern fr unterschiedliche Aufgaben zusammengesetzt und angepaßt werden kBnnen. Beispiel 7-35 implementiert einen Server fr das Internet Time Protocol mit diesem Modul. Benutzen Sie das Skript timeclient zum Ausprobieren. Beispiel 7-35: Benutzung des Moduls SocketServer File: socketserver-example-1.py import SocketServer import time
209
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-35: Benutzung des Moduls SocketServer (Fortsetzung) # Benutzer-zug_nglicher Port PORT = 8037 # Referenzzeit TIME1970 = 2208988800L class TimeRequestHandler(SocketServer.StreamRequestHandler): def handle(self): print "Verbindung von", self.client_address t = int(time.time()) + TIME1970 b = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255) self.wfile.write(b) server = SocketServer.TCPServer(("", PORT), TimeRequestHandler) print "Lausche auf Port", PORT server.serve_forever() Verbindung von ('127.0.0.1', 1488) Verbindung von ('127.0.0.1', 1489) ...
Das Modul BaseHTTPServer Dies ist ein einfaches Rahmenwerk fr HTTP-Server, das auf dem SocketServer-Rahmenwerk aufbaut. Beispiel 7-36 erzeugt jedesmal, wenn Sie die Seite neu laden, eine zuf;llige Nachricht. Die path-Variable enth;lt die aktuelle URL, die Sie dazu verwenden kBnnen, verschiedene Inhalte fr verschiedene URLs zu erzeugen (momentan erzeugt das Skript lediglich eine Fehlerseite fr alles außer dem Wurzelpfad). Beispiel 7-36: Benutzung des Moduls BaseHTTPServer File: basehttpserver-example-1.py import BaseHTTPServer import cgi, random, sys MESSAGES = [ "That's as maybe, it's still a frog.", "Albatross! Albatross! Albatross!", "It's Wolfgang Amadeus Mozart.", "A pink form from Reading.", "Hello people, and welcome to 'It's a Tree.'" "I simply stare at the brick and it goes to sleep.", ]
210
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul SimpleHTTPServer Beispiel 7-36: Benutzung des Moduls BaseHTTPServer (Fortsetzung) class Handler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): if self.path != "/": self.send_error(404, "Datei nicht gefunden") return self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() try: # lenke stdout zum Client um stdout = sys.stdout sys.stdout = self.wfile self.makepage() finally: sys.stdout = stdout # wiederherstellen def makepage(self): # zuf_llige Nachricht erzeugen tagline = random.choice(MESSAGES) print "" print "" print "Zitat des Tages: " print "%s" % cgi.escape(tagline) print "" print "" PORT = 8000 httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler) print "Service an Port", PORT httpd.serve_forever()
Siehe auch die Module SimpleHTTPServer und CGIHTTPServer fr umfassendere HTTP-Rahmenwerke.
Das Modul SimpleHTTPServer Das Modul SimpleHTTPServer ist ein einfacher HTTP-Server, der standardm;ßige GETund HEAD-Request-Handler zur Verfgung stellt. Der durch den Client bergebene Pfadname wird als relativer Dateiname interpretiert (hier ist relativ zu dem aktuellen Verzeichnis, in dem der Server gestartet wurde, gemeint). Die Benutzung des Moduls wird in Beispiel 7-37 demonstriert. Beispiel 7-37: Benutzung des Moduls SimpleHTTPServer File: simplehttpserver-example-1.py import SimpleHTTPServer import SocketServer
211
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-37: Benutzung des Moduls SimpleHTTPServer (Fortsetzung) # Minimaler WebServer. Liefert Dateien relativ zum # aktuellen Verzeichnis. PORT = 8000 Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer(("", PORT), Handler) print "Service an Port", PORT httpd.serve_forever() Service an Port 8000 localhost - - [11/Oct/1999 15:07:44] code 403, message Directory listing not supported localhost - - [11/Oct/1999 15:07:44] "GET / HTTP/1.1" 403 localhost - - [11/Oct/1999 15:07:56] "GET /samples/sample.htm HTTP/1.1" 200 -
Der Server ignoriert Laufwerksbuchstaben und relative Pfadnamen (wie etwa ..). Er implementiert auch keinerlei andere Mechanismen zur Zugriffskontrolle und ist daher mit Vorsicht zu genießen. Beispiel 7-38 implementiert einen wahrlich minimalen Web-Proxy. Wenn HTTP-Anfragen an einen Proxy gesendet werden, sollten sie die volle URI fr den Zielserver enthalten. Dieser Server benutzt urllib, um Daten vom Ziel zu holen. Beispiel 7-38: Verwendung des Moduls SimpleHTTPServer als Proxy File: simplehttpserver-example-2.py # minimaler HTTP-Proxy import SocketServer import SimpleHTTPServer import urllib PORT = 1234 class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): self.copyfile(urllib.urlopen(self.path), self.wfile) httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy) print "Service an Port", PORT httpd.serve_forever()
212
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Das Modul CGIHTTPServer
Das Modul CGIHTTPServer Das in Beispiel 7-39 gezeigte Modul CGIHTTPServer ist ein einfacher HTTP-Server, der externe Skripten ber das Common Gateway Interface (CGI) aufrufen kann. Beispiel 7-39: Benutzung des Moduls CGIHTTPServer File: cgihttpserver-example-1.py import CGIHTTPServer import BaseHTTPServer class Handler(CGIHTTPServer.CGIHTTPRequestHandler): cgi_directories = ["/cgi"] PORT = 8000 httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler) print "Service an Port", PORT httpd.serve_forever()
Das Modul cgi Das Modul cgi liefert eine Reihe von Hilfsfunktionen und Klassen fr CGI-Skripten. Unter anderem kann es CGI-Formulardaten parsen. Beispiel 7-40 zeigt ein einfaches CGI-Skript, das eine Liste von Dateien in einem gegebenen Verzeichnis (relativ zum im Skript angegebenen Wurzelverzeichnis) zurckliefert. Beispiel 7-40: Benutzung des Moduls cgi File: cgi-example-1.py import cgi import os, urllib ROOT = "samples" # Header print "text/html" print query = os.environ.get("QUERY_STRING") if not query: query = "." script = os.environ.get("SCRIPT_NAME", "") if not script: script = "cgi-example-1.py"
213
h:/oreilly/python/python.3d vom 21.11.2001 Seitenformat: 176,00 x 230,00 mm
Kapitel 7: Netzwerkprotokolle Beispiel 7-40: Benutzung des Moduls cgi (Fortsetzung) print print print print print
"" "
" "Dateiauflistung " "" ""
print "" try: files = os.listdir(os.path.join(ROOT, query)) except os.error: files = [] for file in files: link = cgi.escape(file) if os.path.isdir(os.path.join(ROOT, query, file)): href = script + "?" + os.path.join(query, file) print "%s" % (href, cgi.escape(link)) else: print "
%s" % link print "" print "" text/html
Dateiauflistung sample.gif
sample.gz
sample.netrc ...
sample.txt
sample.xml
sample~