Im September erschien Version 2.5 der Skriptsprache Python. Dieser Artikel verrät, welche Veränderungen die neue Ausgabe bringt und ob sich der Umstieg lohnt.
Python hat sich in der Rangliste der beliebtesten Skriptsprachen still und leise nach vorn gearbeitet. Bei Ubuntu ist es neben C die offizielle Entwicklungssprache, auch bei Red Hat gilt Python als Standard zum Skripten. Gründe dafür sind sicherlich die hohe Stabilität der Releases und die große Rückwärtskompatibilität. Die Entwicklung, immer noch gesteuert von Python-Erfinder Guido van Rossum, vollzieht sich vorwiegend evolutionär, nur gelegentlich gibt es größere Änderungen am Sprachkern.
Die letzte größere Python-Release ist mit Version 2.4 beinahe zwei Jahre alt. Jetzt ist mit Python 2.5 eine neue Ausgabe mit interessanten Neuerungen erschienen, von kleineren über größere Spracherweiterungen bis hin zu neuen Modulen [1].
Neue Bedingung
Für die einen leicht entbehrlich, von anderen lange vermisst, hat Python nun auch einen Bedingungsausdruck, ähnlich dem C-Idiom »Bedingung ? Falls_wahr : Falls_falsch«. In Python schreibt sich das Konstrukt so: »Falls_wahr if Bedingung else Falls_falsch«. Der Ausdruck, der im Fall einer wahren Bedingung zu ermitteln ist, steht also vor der Bedingung. Das folgende Beispiel bildet die eingebaute Funktion »max« für zwei Werte a und b nach:
maximum = (a if a > b else b)
Die Klammern sind nur optional, sie machen die Anweisung aber leichter verständlich.
Manche Programmierer finden, dass der ternäre Ausdruck generell überflüssig sei, da er sich auch anders ausdrücken lässt. Zum Beispiel funktioniert statt des obigen Code auch »maximum = (b, a)[a > b]«. Sind »a« und »b« allerdings Ausdrücke, wertet der Interpreter im Gegensatz zum neuen Konstrukt immer beide aus, was zu unerwarteten Seiteneffekten führen kann. Laut [2] kam der ternäre Operator vor allem deshalb hinzu, weil viele Programmierer bei seiner Nachbildung so oft Fehler machen.
Schon seit langem gibt es in Python »try … except … else« zur Ausnahmebehandlung sowie »try … finally« für das sichere Aufräumen, zum Beispiel das Schließen einer Datei. Oft treten beide Varianten kombiniert auf, zum Beispiel um beim Lesen einer Datei unterschiedliche Exceptions abzufangen (Listing 1). Python 2.5 führt eine kompaktere Schreibweise ein, die verschachtelte Try-Anweisungen erspart (Listing 2).
|
Listing 1: Verschachtelte |
|---|
01 datei = open("zahlen.dat")
02 try:
03 try:
04 zahlen = [int(zeile) for zeile in datei]
05 except ValueError:
06 print "Nicht alle Zeilen sind Zahlen."
07 else:
08 print "Alle Zeilen erfolgreich eingelesen."
09 finally:
10 datei.close()
|
|
Listing 2: Kombinierte |
|---|
01 datei = open("zahlen.dat")
02 try:
03 zahlen = [int(zeile) for zeile in datei]
04 except ValueError:
05 print "Nicht alle Zeilen enthalten Zahlen."
06 else:
07 print "Alle Zeilen erfolgreich eingelesen."
08 finally:
09 datei.close()
|
Heimlich aufräumen
Wie bereits angesprochen, dient »try … finally« zum Aufräumen von Ressourcen, zum Beispiel dem Freigeben von Locks. Die neue »with«-Anweisung [3] hilft dabei, oft wiederkehrende Aufräumarbeiten zu verstecken (Listing 3). Den logischen Ablauf zeigt das UML-Diagramm in Abbildung 1.

Abbildung 1: Die neue With-Anweisung in Python 2.5 nimmt dem Programmierer manuelle Aufräumarbeiten ab: Am Ende eines entsprechenden Blocks (»__exit__«) schließt der Interpreter beispielsweise offene Dateien.
|
Listing 3: |
|---|
01 from __future__ import with_statement
02
03 with open("zahlen.dat") as datei:
04 try:
05 zahlen = [int(zeile) for zeile in datei]
06 except ValueError:
07 print "Nicht alle Zeilen enthalten Zahlen."
08 else:
09 print "Alle Zeilen erfolgreich eingelesen."
|
Wie bei »try … finally« schließt Python die Datei nach dem »with«-Block, egal ob ein Fehler auftrat oder nicht. Objekte, die nach dem »with«-Schlüsselwort folgen, müssen das so genannte Kontextmanager-Protokoll unterstützen. Standardmäßig trifft dies auf Datei- und verschiedene Lock-Objekte aus dem »threading«-Modul zu.
Eigene Kontextmanager lassen sich mit einer Klasse erstellen, die über die speziellen Methoden »__enter__« und »__exit__« verfügt. In einfacheren Fällen hilft das »contextlib«-Modul bei der Erzeugung eines Kontextmanagers.
Importe absolut und relativ
Gelegentlich kann es vorkommen, dass ein Modul eines eigenen Projekts ein Modul aus der Standard-Distribution verdeckt. Als Beispiel sei angenommen, dass ein Python-Paket die folgende Datei- und Verzeichnisstruktur besitzt:
paket/
__init__.py
string.py
modul.py
Enthält nun »modul.py« eine Anweisung »import string«, bezieht sich diese auf die Datei »string.py« in dem Paket »paket«; das Modul »string« aus der Python-Distribution ist nicht mehr ohne weiteres zugänglich.
Wenn nun mit der Python-2.5-Version die Anweisung »from __future__ import absolute_import« am Dateianfang steht, beziehen sich Import-Anweisungen immer auf die Verzeichnisse in »sys.path« (so genannter absoluter Import). Im Beispiel lädt Python dann das »string«-Modul aus der Standardbibliothek, während das Modul des Pakets wie in bisherigen Python-Versionen durch »import paket.string« oder »from paket import string« zugänglich ist.
Absolute Importe haben allerdings den Nachteil, dass bei einer Änderung der Paketstruktur unter Umständen viele Module zu editieren sind. Deshalb bleiben relative Importe dank einer neuen Syntax immer noch möglich. Mit »from . import string« lädt der Interpreter das »string«-Modul aus dem Paket.
Bei tiefer verschachtelten Verzeichnisstrukturen können auch Anweisungen der Art »from ..modul import Name« vorkommen. Das bedeutet für den Python-Interpreter: Importiere das Objekt »Name« aus dem Modul »modul.py«, das zwei Verzeichnisebenen weiter oben zu finden ist.
Die Distutils-Infrastruktur hat sich in Python-Kreisen seit längerem etabliert, um Python-Pakete zu erstellen und zu installieren [4]. Nun unterstützen die Distutils noch einige zusätzliche Parameter. Besonders interessant ist »requires«, da sich hiermit notwendige Pakete automatisch installieren lassen. Damit wird der Python Package Index (Cheese Shop, [5]) noch vielseitiger. Das Setuptools-Projekt [6] bietet diese (und weitere) Funktionalität ebenfalls, muss aber zusätzlich zu Python installiert werden.
Neue Module
In der neuen Python-Version sind zwei Module enthalten, die es schon länger gibt, bisher aber getrennt von der Distribution. Bei »ElementTree« [7] handelt es sich um eine leicht zu verwendende Bibliothek zum Parsen, Verändern und Serialisieren von XML. Das Beispielprogramm aus Listing 4 liest einen RSS-Feed von der Website des Informationsdienstes Wissenschaft [8] und gibt Titel und Beschreibungen jener Einträge aus, die das Wort »Forschung« enthalten. Leider neigt Element Tree dazu, beim Parsen Namensraumpräfixe umzubenennen [9], was die Bibliothek manchmal umständlich verwendbar macht.
|
Listing 4: RSS-Feed-Analyse mit |
|---|
01 import urllib
02 import xml.etree.ElementTree as et
03
04 TRENNER = 79 * "="
05 AUSGABE_ENCODING = "latin1"
06
07 def filter_rss(url, text):
08 rss_file = urllib.urlopen(url)
09 rss_tree = et.parse(source=rss_file)
10 rss_file.close()
11 for item in rss_tree.getiterator("item"):
12 titel = item.findtext("title")
13 beschreibung = item.findtext("description")
14 if (text in titel) or (text in beschreibung):
15 print TRENNER
16 print titel.encode(AUSGABE_ENCODING)
17 print
18 print beschreibung.encode(AUSGABE_ENCODING)
19 print
20
21 if __name__ == '__main__':
22 filter_rss("http://idw-online.de/pages/de/pressreleasesrss",
23 u"Forschung")
|
Ebenfalls neu in der Python-Distribution ist das »ctypes«-Modul. Damit lassen sich – ohne das Schreiben von Python-Erweiterungen in C – externe C-Bibliotheken benutzen. Abbildung 1 zeigt einige Beispiele für die C-Standardbibliothek. Es gibt auch eine Schnittstelle zu Pythons C-API.
Daneben sind die Module »hashlib« (für die Berechnung verschiedener Hashfunktionen), »sqlite3« (Wrapper für eine bereits installierte Sqlite-Bibliothek) sowie »wsgiref« (eine Referenz-Implementierung für das Webserver Gateway Interface WSGI, [10]) hinzugekommen. Das WSGI definiert eine Standardschnittstelle zwischen Webservern und Python-Webframeworks.
Generatorerweiterungen
Python 2.3 hat Generatoren eingeführt, die sich für verschiedene Anwendungen als nützlich erwiesen haben. Konnten Generatorfunktionen bisher (über »yield«) nur Werte liefern, ist es nun ebenfalls möglich, Werte oder auszulösende Ausnahmen in Generatorfunktionen hineinzureichen. Mit dieser Infrastruktur lassen sich Koroutinen [11] implementieren. Die sind zwar sehr leistungsfähig, aber auch relativ kompliziert anzuwenden. Offen bleibt, ob Koroutinen breitere Anwendung finden werden oder ob sie ein ähnliches Schicksal erleiden wie die seit langem verfügbaren Metaklassen [12], die eher ein Schattendasein fristen.
Eingebaute Ausnahmen sind die New-Style-Klassen, die schon seit Python 2.2 Deskriptoren zur vielseitigeren Steuerung des Attributzugriffs und eine sinnvolle Attribut-Suchregel bei Mehrfachvererbung ermöglichen. »KeyboardInterrupt« und »SystemExit« leiten nicht mehr von »Exception« ab. Das macht es einfacher, diese Sonderfälle von einer allgemeinen Ausnahmebehandlung auszunehmen. Die Kommandozeilenoption »-m« kann nun auch Module in Paketen oder Zip-Dateien ausführen. Daneben gibt es ein paar kleinere Änderungen, Fehlerkorrekturen und Optimierungen.
|
Listing 5: Zugriff auf die Libc |
|---|
01 >>> import ctypes
02 >>> libc = ctypes.CDLL('libc.so.6')
03 >>>
04 >>> # Default: Rückgabe eines Integers
05 >>> ergebnis = libc.printf("Hallo Welt!n")
06 Hallo Welt!
07 >>> ergebnis # Anzahl der Zeichen
08 12
09 >>>
10 >>> # Anpassungen für anderen Rückgabetyp
11 >>> libc.atof('2.71828')
12 -1783957616
13 >>> libc.atof.restype = ctypes.c_double
14 >>> libc.atof('2.71828')
15 2.71828
16 >>>
17 >>> # Anpassung eines Parameters
18 >>> s = "ein String"
19 >>> puffer = ctypes.create_string_buffer(s)
20 >>> libc.strfry.restype = ctypes.c_char_p
21 >>> libc.strfry(puffer)
22 'gie rtSnin'
|
Verbesserungen
Vor allem jene Programmierer, die mit C und davon abgeleiteten Sprachen arbeiten, werden sich freuen, dass nun auch Python einen ternären Bedingungsausdruck anbietet.
Aufräumarbeiten wie das Schließen von Dateien oder Sockets sind jetzt einfacher. Zum einen müssen »try … finally« und »try … except« nicht mehr ineinander verschachtelt sein. Das macht den Code etwas übersichtlicher. Zur neuen »with«-Anweisung ist das Kontextmanager-Protokoll hinzugekommen, das dem Programmierer hilft Aufräumarbeiten noch weiter zu systematisieren.
Die neue Notation für relative Importe dürfte das Leben der Betreuer umfangreicher Python-Pakete erleichtern. Mit den neuen Metadaten, insbesondere den Abhängigkeiten von anderen Paketen, nähert sich der Python Package Index in seiner Funktionalität Perls Modul-Repository CPAN.
Das »ElementTree«-Paket erleichtert die Arbeit mit XML-Dateien, weist aber noch ein paar Macken im Zusammenhang mit XML-Namensräumen auf. Das »ctypes«-Modul hilft dem fortgeschrittenen Python-Programmierer bei der Verwendung von C-Bibliotheken. Das Programmieren von C-Erweiterungen direkt mit Pythons C-API dürfte damit in Zukunft weitaus seltener erforderlich sein.
Laufende Generatorfunktionen sind jetzt von außen manipulierbar, was der Implementierung von Koroutinen entspricht. Es wird sich zeigen, ob die meisten Python-Programmierer hier eher zu elegantem oder eher zu schwer verständlichem Code neigen – oder ob die neue Funktionalität wenig genutzt bleibt.
Vorsicht beim frühen Umstieg
Python 2.5 enthält gegenüber der Vorversion einige bemerkenswerte Neuerungen, die zu einem schnellen Umstieg verlocken. Jeder Programmierer sollte jedoch bei einem Versionswechsel immer bedenken, dass die eigene Software womöglich auch mit älteren Python-Installationen zusammenarbeiten muss. Wer jetzt sofort wechseln will, sollte also vorher die Portierungshinweise in [1] genau lesen. (ofr)
|
Infos |
|---|
|
[1] Neues in Python 2.5: [http://docs.python.org/whatsnew/whatsnew25.html] [2] Conditional Expressions: [http://www.python.org/dev/peps/pep-0308/] [3] With-Anweisung: [http://www.python.org/dev/peps/pep-0343/] [4] Distutils: [http://docs.python.org/lib/module-distutils.html] [5] Python-Paketdatenbank: [http://www.python.org/pypi] [6] Setuptools: [http://peak.telecommunity.com/DevCenter/setuptools] [7] Element Tree: [http://effbot.org/zone/element-index.htm] [8] Informationsdienst Wissenschaft: [http://idw-online.de] [9] Element Tree und Namensräume: [http://mail.python.org/pipermail/python-dev/2006-August/thread.html#68171] [10] WSGI: [http://www.xml.com/lpt/a/1674] [11] Koroutinen: [http://koroutine.informatik-info.net/] [12] Metaklassen: [http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses] |
|
Der Autor |
|---|
|
Dr.-Ing. Stefan Schwarzer ist selbstständiger Software-Entwickler, verwendet Python seit 1999 und hat bei Addison-Wesley das Buch “Workshop Python” veröffentlicht. |
Copyright © 2002 Linux New Media AG





