Die Programmiersprache Python – ein Überblick

Stefan Schwarzer
29. Juni 2001
Rechenzentrum der TU Clausthal

Python ist eine relativ einfach zu lernende aber dennoch ausdrucksstarke Skriptsprache (d. h. es ist kein expliziter Übersetzungsvorgang durch einen Compiler notwendig). Python ist im Quelltext für viele Plattformen verfügbar und darf (auch in modifizierter Form) in eigenen Produkten benutzt werden.

Im Rechenzentrum wird Python zur Neuentwicklung der Software für den Informationsdienst Wissenschaft (idw) verwendet.

Die Anwendungsgebiete von Python sind ähnlich denen des bekannteren Perl, bspw. Verarbeitung von ASCII-Dateien, Systemadministration und Web-Programmierung. Jedoch ist Python im Allgemeinen lesbarer, unterstützt neben der herkömmlichen prozeduralen Programmierung die objektorientierte Programmierung besonders gut und ist daher besser skalierbar als bspw. Perl.

Überblick

Einführung

Ursprung

Python (benannt nach "Monty Python") geht auf Guido van Rossum zurück, der damit eine leicht zu lernende, gut lesbare und leistungsfähige Sprache schaffen wollte. Einige Spracheigenschaften stammen von ABC.

Stärken von Python

  • leicht zu lernen
  • leicht zu lesen ("pseudocode that actually runs") und zu warten
  • (relativ) leicht zu schreiben
  • auch gut geeignet zur Erstellung von Prototypen
  • gut skalierbar

Lizenz

Python ist Open Source-Software und darf kostenlos mit oder ohne Änderungen in freier und kommerzieller Software verwendet und verbreitet werden.

Einsatzgebiete

  • Textverarbeitung, XML
  • Systemadministration
  • Systemintegration ("glue language")
  • Internet-Programmierung (HTML, HTTP, FTP, SMTP, CGI etc.)
  • GUI-Programmierung (TKinter, wxPython etc.)
  • Numerik (NumPy, mit Erweiterungen in C)
  • Bildverarbeitung (Python Image Library, PIL, mit Erweiterungen in C)

Ressourcen

Links

Bücher

  • Ein gutes Lehrbuch zu Python ist "Learning Python" von O'Reilly, geschrieben von Mark Lutz und David Ascher, das auch in einer deutschen Übersetzung ("Einführung in Python") von Christian Tismer vorliegt. Dieses Buch ist allerdings noch auf dem Stand der Python-Version 1.5.2; aktuell ist 2.1 (zum Zeitpunkt des Vortrags).
  • Ein weiterführendes Buch ist "Programming Python" von Mark Lutz, ebenfalls erschienen O'Reilly. Dieses Buch setzt den Schwerpunkt bei Anwendungen (bspw. Textverarbeitung, GUI-Entwicklung und Internet-Programmierung). Das Buch ist auf dem Stand von Python 2.0.
  • Addison-Wesley hat "Python 2" von Martin von Löwis und Nils Fischbeck veröffentlicht. Es ist eine Einführung in Python, enthält aber auch Anwendungsbeispiele für Fortgeschrittene.
  • Weitere Literaturhinweise gibt es im "Python Bookstore".

Datentypen

In Python gibt es drei Gruppen von Datentypen:

  • Skalare haben als Untertypen Ganzzahl (integer), Ganzzahl mit beliebig vielen Stellen (long integer), Fließkommazahlen (float), komplexe Zahlen (complex) und Zeichenketten (string).
        i = 1; li = 9999999999L; f = 3.14; c = 3+4j; s = 'Hello'
          
    Es gibt keinen expliziten Zeigertyp.
  • Sequenzen (sequence) nehmen eine feste Folge anderer Objekte auf. Das können bspw. auch weitere Sequenzen sein. Sequenzen werden weiter unterteilt in Listen (list) und Tupel (tuple).
        L = [1, 3];  L.append(7);  print L[2]
          
    gibt 7 aus, während
        T = (1, 3);  T.append(7)
          
    eine Fehlermeldung erzeugt. Tupel können, wenn einmal erzeugt, nicht mehr - ohne Neuzuweisung - verändert werden.
  • Assoziative Listen (dictionaries) erlauben den Zugriff auf Werte auch über nicht-numerische Schlüssel:
        D = {'b': 'Python', 'a': 5};  print D['a']
            
    gibt 5 aus. Als Schlüssel (keys) können beliebige unveränderliche Datentypen (bspw. ganze und Fließkommazahlen, aber auch Tupel) verwendet werden.
  • Der Typ einer Variablen wird durch Zuweisung festgelegt. Anders als in Pascal, C, C++ oder Java ist es in Python (bisher) nicht vorgesehen, Namen mit Datentypen zu verknüpfen. Der folgende Code ist gültiges Python.
        a = 7                       # 7 (integer)
        a = a / 2.0                 # 3.5 (float)
        a = str(2*a) + ' Bytes'     # '7 Bytes' (string)
        

Operatoren

Python besitzt die folgenden Operatoren

    () [] {} ``  [:] . + - ~ ** * / % << >> & ^ |
    is in < <= > >= == <> != not and lambda or
Seit Python 2.0 gibt es außerdem die Operatoren
    += -= **= *= /= %= <<= >>= &= ^= |=

Anweisungsfolgen

  • In Python stehen Anweisungen, die zur selben logischen Gruppe gehören, auf einzelnen Zeilen und gleichmäßig eingerückt:
        if a > 0:
            b = 1
            c = 2
        
  • Es ist kein Zeichen (z. B. "}") nötig, um einen Anweisungsblock abzuschließen. Verwendet man Semikola, kann man, wie in den Beispielen weiter oben, auch mehrere Anweisungen auf eine Zeile schreiben.
  • Eine Anweisung wird fortgesetzt, wenn am Ende der vorhergehenden Zeile ein Backslash \ steht oder noch Klammern "offen sind."

Bedingte Anweisungen

  • Python kennt die bedingte Ausführung mit if, elif (nicht: elsif oder elseif) und else.
  • Beispiel:
        if a > b:
            print 'a ist groesser als b.'
        elif a < b:
            print 'a ist kleiner als b.'
        else:
            print 'a ist gleich b.'
          
  • Python erlaubt "abgekürzte" Bereichsabfragen.
        if 2 <= a <= 7: print 'a liegt im Intervall [2, 7].'
          

Schleifen

  • In Python werden Schleifen mit for oder while definiert.
  • Das folgende Beispiel sammelt mit einer while-Schleife alle Zahlen von 0 bis 99 in einer Liste.
        liste = []
        i = 0
        while i < 100:
            liste.append(i)
            i = i + 1   # oder  i += 1  seit Python 2.0
        
  • Die for-Schleife sieht so aus:
        liste = []
        for i in range(100):
            liste.append(i)
        
  • Anstatt der obigen expliziten Schleifen lässt sich auch eine implizite Schleife angeben:
        liste = range(100)
        
    range(100) erzeugt eine Liste aller ganzen Zahlen von 0 bis 99, nicht bis 100.
  • Mit for kann man nicht nur über Listen von ganzen Zahlen, sondern über beliebige Sequenzen iterieren:
        for programmiersprache in [C, Perl, Python, Pascal]:
            erklaere(programmiersprache)
        
  • Python verwendet break zum "vorzeitigen" Verlassen von Schleifen.
        gefunden = 0
        for eintrag in eintraege:
            if gesucht == eintrag:
                gefunden = 1
                break
        
  • Mit continue kann man direkt zum Anfang des Schleifenrumpfes springen, in dem die continue-Anweisung steht.
        # Quadrate der positiven Zahlen in der Liste ausgeben
        X = [1, -1, 2.4, -5.7]
        for num in X:
            if num <= 0: continue
            print 'Zahl:', num, '  Quadrat:', num*num
        
    erzeugt die Ausgabe
        Zahl: 1   Quadrat: 1
        Zahl: 2.3   Quadrat: 5.76
        
  • Es gibt mehrere Anweisungen, die implizit Schleifen ausführen. Eine davon ist map (zur Bedeutung der lambda-Anweisung siehe den Abschnitt über Funktionen):
        X = [1, -1, 2.4, -5.7]
        Y = map(lambda num: num*num, X)
        # Ab Python 2.0 auch einfacher als
        # Y = [num*num for num in X]
        print Y
        
    Die Ausgabe ist
        [1, 1, 5.76, 32.49]
        

Anwendungsbeispiel

Es soll eine Datei eingelesen, zeilenweise sortiert und in eine Datei mit der zusätzlichen Endung '.sortiert' geschrieben werden. Mit Python kann man das - in Anlehnung an "normale" Programmiersprachen - so machen:

    #!/usr/bin/python

    import sys

    # Dateiname ermitteln
    dateiname = sys.argv[1]  # Skriptname steht in sys.argv[0]
    zeilen = []

    # Datei lesen
    try:
        datei = open(dateiname, 'r')
        while 1:
            zeile = datei.readline()
            if zeile == '':
                break
            zeilen.append(zeile)
        datei.close()
    except IOError:
        print dateiname, "ist nicht lesbar"
        sys.exit(1)

    # sortieren
    zeilen.sort()
    dateiname = dateiname + '.sortiert'

    # Datei schreiben
    try:
        datei = open(dateiname, 'w')
        for zeile in zeilen:
            datei.write(zeile)
        datei.close()
    except IOError:
        print dateiname, "ist nicht schreibbar"

Dies geht auch kürzer:

    #!/usr/bin/python
    import sys

    # Dateiname ermitteln
    dateiname = sys.argv[1]

    # Datei lesen
    try:
        datei = open(dateiname, 'r')
        zeilen = datei.readlines()
        datei.close()
    except IOError:
        print dateiname, "ist nicht lesbar"
        sys.exit(1)

    # Datei sortieren
    zeilen.sort()
    dateiname = dateiname + '.sortiert'

    # Datei schreiben
    try:
        datei = open(dateiname, 'w')
        datei.writelines(zeilen)
        datei.close()
    except IOError:
        print dateiname, "ist nicht schreibbar"
Unter Verzicht auf Fehlerprüfung (Vorgehensweise "schnell und schmutzig" ;-) ) lässt sich das Programm noch weiter kürzen:
    #!/usr/bin/python
    from sys import argv

    zeilen = open( argv[1], 'r' ).readlines()
    zeilen.sort()
    open( argv[1] + '.sortiert', 'w' ).writelines(zeilen)

Unterprogramme

  • Unterprogramme werden in Python mit den Schlüsselwörtern def und lambda definiert.
  • Der Funktionsrumpf wird eingerückt.
  • Die Argumente werden als benannte Variablen übergeben.
  • Es können beliebige Python-Datenstrukturen an den Aufrufer zurückgegeben werden.
  • Es kann ein Rückgabewert in der return-Anweisung angegeben werden, wenn nicht, ist der Rückgabewert der besondere Wert None.
  • Vorgabeargumente (wie in C++) sind erlaubt.
  • Im Aufruf darf die Reihenfolge der Parameter verändert werden, wenn sie entsprechend benannt werden.
  • Diese Funktion liefert den Index eines Wertes gesucht in der Sequenz eintraege. Fehlt der Wert, wird None zurückgeliefert.
        def index(gesucht, eintraege):
            "Suche den Wert 'gesucht' in der Sequenz 'eintraege'"
            for i in range( len(eintraege) ):
                if eintraege[i] == gesucht:
                    return i
            return None                         # nicht gefunden
    
        print index( 3, [1, 2, 3, 4] )          # suche 3 in der Liste
        print index( eintraege=[1, 2, 3, 4],    # alternative
          gesucht=3 )                           #   Formulierung
        
  • Falls nur ein Ausdruck aus den Argumenten zu berechnen ist, kann die lambda-Anweisung nützlich sein. Statt
        def quadrat(x):
            return x * x
        
    lässt sich schreiben
        quadrat = lambda x: x*x
        
    Lambda-Funktionen sind besonders in Anweisungen gefragt, die eine gegebene Funktion auf die Elemente einer Sequenz anwenden. Hier kann man eine anonyme (d. h. unbenannte) Funktion erzeugen (s. das obige Beispiel mit map).

Module

Allgemeines

  • Module sind Programmteile, die in eigene Dateien geschrieben werden, um sie in mehreren Programmen verwenden zu können.
  • Die Nutzbarkeit in mehreren Zusammenhängen muss beim Entwurf eines Moduls bewusst berücksichtigt werden.
  • Wenn es nicht ausdrücklich anders definiert wird, muss bei Verwendung eines Befehls aus einem Modul im Hauptprogramm (oder einem anderen Modul) der Modulname explizit genannt werden (s. Beispiele unten).

Module in Python

Grundlagen

  • Die Python-Distribution enthält neben Interpreter und Dokumentation eine große Anzahl an Modulen (ca. 200 in Python 2.1), bspw. zur Textverarbeitung und zur einfachen Verwendung von Internet-Protokollen.
  • Moduldateien haben die Endung .py, genau wie "normale" Programme. Es ist so möglich, dieselbe Datei als Modul oder als eigenständiges Programm zu verwenden.
  • Es gibt keine besondere Anweisung, um ein Modul als solches zu kennzeichnen. Ein Modul unterscheidet sich von einem Programm nur durch die Verwendung, nicht durch speziellen Code.
  • Ein einfaches Modul ist
        #!/usr/bin/python
        # EinModul.py
        # Definiere das Modul EinModul
    
        var1 = 1
        var2 = [2, 3]
    
        def quadrat(x):
            return x * x
        
  • In andere Dateien wird das Modul durch eine import-Anweisung geladen.
  • Namen des geladenen Moduls wird der Modulname, gefolgt von einem Punkt, vorangestellt. Beispiel:
        #!/usr/bin/python
        # Hauptprogramm
    
        import EinModul
    
        test = EinModul.var1            # test = 1
        test = EinModul.quadrat(7)      # test = 49
        

Exportieren und Importieren von Namen

  • Exportieren von Namen aus einem Modul heißt, dass diese Namen ohne Angabe des Modulnamens benutzt werden können (bzw. müssen). Aus der Sicht des Programms, das ein Modul verwenden möchte, spricht man von importieren von Namen.
  • Welche Namen eines Moduls in ein Programm importiert werden, wird üblicherweise vom importierenden Programm gesteuert und nicht vom geladenen Modul.
  • Namen eines Moduls können importiert werden, indem import zusammen mit from benutzt wird. Sonst wird nur der Name des Moduls importiert.
        from EinModul import var1           # importiere nur var1;
                                            #  test = var1  ist damit möglich
    
        from EinModul import var1, var2     # importiere var1 und var2
    
        from EinModul import *              # importiere (fast) alles
        
    Mit der letzten Form werden alle Namen importiert, die nicht mit _ beginnen.

Häufig verwendete Python-Module

  • sys, os für grundlegende Interaktionen mit dem Betriebssystem
        import sys, os
        print sys.argv[1:]              # gebe Kommandozeilen-Argumente aus
        os.system('ls -l')              # zeige unter Unix ein Verzeichnis an
        
  • string für Zeichenkettenverarbeitung; ab Python 2.0 wird das Modul kaum noch explizit benutzt, da nun auch Zeichenketten Methoden haben
        import string
        print string.split('2001-06-29', '-')   # ['2001', '06', '26']
        
    ab Python 2.0:
        print '2001-06-29'.split('-')
        
  • math für bestimmte mathematische Funktionen
        import math
        print math.sin(1.0)             # 0.841470984808
        
  • re zur Verarbeitung regulärer Ausdrücke
        import re
        pattern = re.compile(r'[A-Za-z]+')
        text = 'Fri 26 June 2001, 26Jun2001'
        print pattern.findall( text )   # ['Fri', 'June', 'Jun']
        
  • time zum Arbeiten mit Zeit-Werten
        import time
        # 2001-06-29 (bzw. das heutige Datum)
        print time.strftime( '%Y-%m-%d', time.localtime(time.time()) )
        
    oder auch
        from time import strftime, localtime, time
        print strftime( '%Y-%m-%d', localtime(time()) )
        

Objektorientierte Programmierung

Allgemeines

  • Objekte bieten Variablen und Funktionen (Methoden), die auf diese Daten wirken. Zum Beispiel soll ein Ofen die Variablen
    • Temperatur (in °C)
    • Klappe auf/zu
    und die Funktionen
    • klappe_oeffnen (kein Parameter)
    • klappe_schliessen (kein Parameter)
    • fuellen (Parameter: Material)
    • aufheizen (Parameter: Endtemperatur in °C)
    • abkühlen (kein Parameter)
    haben.
  • Es kann mehrere Objekte der selben Art (Instanzen) geben (in unserem Beispiel mehrere Öfen), die unabhängig voneinander sind.
  • Die Schnittstelle zwischen Objekt und verwendendem Programmcode soll nur offenlegen, was getan wird, aber möglichst nicht, wie es getan wird. Letzteres bleibt "Privatangelegenheit" des Objekts.
  • Objekttypen (Klassen) können als Basis für ähnliche, spezialisierte Typen dienen. Die Ableitung neuer Klassen von bereits bestehenden nennt man Vererbung. Übertragen auf das obige Beispiel könnte man aus der bestehenden Klasse Ofen eine neue Klasse Umluftherd erzeugen, bei der zusätzlich die Umluft ein- und ausgeschaltet werden kann.

Objektorientierte Programmierung in Python

  • Eine Klasse wird mit der class-Anweisung erzeugt.
  • Der Konstruktor, __init__, erzeugt eine neue Instanz. Die Verbindung von Objektinstanz und Klasse geschieht implizit.
  • Der Konstruktor kann die neue Instanz mit Werten initialisieren.
  • Methoden einer Klasse erhalten die Objektreferenz als ersten Parameter.
  • Eine Klasse kann von einer (oder mehreren) anderen erben, indem der Name der "beerbten" Klasse als Argument der class-Anweisung eingesetzt wird.
  • Eine mögliche Implementierung der oben beschriebenen Klasse ist
        # ofen.py
    
        class Ofen:
            def __init__(self):
                self.temperatur = 20        # Raumtemperatur
                self.klappe_auf = 0         # Klappe zu
                self.material = None        # Ofen ist leer
    
            def klappe_oeffnen(self):
                if self.temperatur > 20:
                    print "Bitte vor dem Oeffnen der Klappe den Ofen abkuehlen!"
                    return
                self.klappe_auf = 1
    
            def klappe_schliessen(self):
                self.klappe_auf = 0
    
            def fuellen_mit(self, material):
                if not self.klappe_auf:
                    print "Bitte vor dem Fuellen die Klappe oeffnen!"
                    return;
                self.material = material
    
            def aufheizen(self, temperatur):
                if self.klappe_auf:
                    print "Bitte vor dem Aufheizen die Klappe schliessen!"
                    return
                self.temperatur = temperatur
    
            def abkuehlen(self):
                self.temperatur = 20
    
    
        # ----------------------------------------------------------------
        # umluftherd.py
    
        import ofen
    
        class Umluftherd(ofen.Ofen):
            def __init__(self):
                ofen.Ofen.__init__(self)
                self.umluft = 0
    
            def umluft_an(self):
                self.umluft = 1
    
            def umluft_aus(self):
                self.umluft = 0
    
    
        # ----------------------------------------------------------------
        # ofentest.py
    
        #!/usr/bin/python
    
        import umluftherd, time
    
        herd = umluftherd.Umluftherd()
        herd.klappe_oeffnen()
        herd.fuellen_mit('Teig')
        herd.klappe_schliessen()
        herd.umluft_an()
        herd.aufheizen(250)
        time.sleep(60*60)                   # eine Stunde backen
        herd.abkuehlen()
        herd.umluft_aus()
        

Weitere Beispiele

  • eine HTML-Seite von einem Server holen und ausgeben
        import urllib
        page = urllib.urlopen('http://www.ndh.net/home/sschwarzer/python/')
        print page.read()
        page.close()
        
  • eine Mail versenden
        import smtplib
        mailhost = smtplib.SMTP( 'mail.tu-clausthal.de' )
        text = \
        """From: Stefan.Schwarzer@tu-clausthal.de
        To: Stefan.Schwarzer@tu-clausthal.de
        Subject: Demo-Mail
    
        Ein kleiner Demo-Text."""
        mailhost.sendmail( 'Stefan.Schwarzer@tu-clausthal.de',
          ['Stefan.Schwarzer@tu-clausthal.de'], text )
        mailhost.quit()
        
  • mit komplexen Zahlen rechnen (Ausgaben sind fett dargestellt)
        import math, cmath
        print math.sin(1.0)
        0.841470984808
        print math.sin(1+3j)
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        TypeError: can't convert complex to float; use e.g. abs(z)
        print cmath.sin(1+3j)
        (8.4716454543+5.41268092318j)
        
  • Userdaten ermitteln und ausgeben
    Hierzu werden das Modul user_data_list.py und die auszuführende Datei userdata.py erklärt. Das Beispiel läuft ab Python 2.0. (Die Syntaxhervorhebung wurde mit py2html von Marc-Andre Lemburg und PyFontify von Just van Rossum erzeugt.)

Abschließende Bemerkungen

  • Auch für Python (genauer: alle Sprachen) gilt: Erst denken, dann schreiben :-)
  • Auch in Python kann man unverständliche Programme schreiben, wenn man nicht aufpasst.
  • Die Zeit, die man in Python bei der "Implementation im Kleinen" spart (Fehlersuche!), kann man zum Herausfinden von besserem Programmdesign und besseren Algorithmen verwenden.

URL of this page: http://www.sschwarzer.net/python/python_vortrag.html