Perl und Python - Zwei Skriptsprachen im Vergleich

Stefan Schwarzer
13. Mai 2000
Zweite Braunschweiger Linux-Tage

Überblick

Was sind Skriptsprachen?

Es gibt anscheinend keine einheitliche Definition von "Skriptsprache." Üblicherweise werden aber folgende Eigenschaften angenommen:

  • Die Sprache wird nicht - explizit - kompiliert oder mit Bibliotheken verbunden. Dies geschieht hinter den Kulissen; ein veränderter Quelltext ändert sein Verhalten bei der nächsten Ausführung.
  • Typdeklarationen für Variablen sind freiwillig und/oder gar nicht möglich.
  • "Höhere" Skriptsprachen, darunter Perl und Python, bieten komplexe Datenstrukturen (Listen, assoziative Listen) und dazu gehörige Operationen.

Ursprünge

Perl

Perl (Practical extraction and report language) wurde von Larry Wall entwickelt, um - wie der Name der Sprache verrät - Zusammenfassungen von Programmausgaben zu erzeugen. Wall orientierte sich vor allem an Shell-Skriptsprachen und C.

Die Einstiegsseite für Perl ist http://www.perl.com/.

Python

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.

Die erste Anlaufstelle für Python ist http://www.python.org/.

Datentypen

Perl

Perl kennt drei Gruppen von Datentypen, die durch unterschiedliche Präfixe gekennzeichnet werden:

  • Skalare, z. B. $zahl. Skalare nehmen Zahlen (number), Zeichenketten (string) oder Zeiger (reference) auf. Die Interpretation einer Variable kann durch die darauf angewendeten Operatoren beeinflusst werden.
        $a = 17; $b = 2;  print $a > $b;
    
    ergibt 1 (wahr),
        $a = 17; $b = 2;  print $a gt $b;
    
    ergibt '' (falsch), weil $a und $b zum Vergleich in die Zeichenketten '17' und '2' gewandelt werden.
  • Listen (array), z. B. @liste. Listen enthalten Skalare in einer "festen" Reihenfolge, die nur durch das Programm verändert werden kann.
        @liste = (1, 3);  push @liste, 7;  print $liste[2];
    
    gibt 7 aus. (Das erste Element der Liste hat den Index Null.)
  • Assoziative Listen (hash), z. B. %hash. Hashes speichern Werte (values), auf die über Schlüssel (keys) zugegriffen wird.
        %hash = (b => 'Perl', a => 5);  print $hash{a};
    
    gibt den Wert 5 aus, der zum Schlüssel a gehört.

Python

Auch in Python gibt es die drei Gruppen von Datentypen, wie sie in Perl vorkommen. Jedoch sind sie nicht besonders markiert und sind weiter unterteilt:

  • 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, vgl. das Listenbeispiel bei Perl, 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) entsprechen den Hashes in Perl:
        D = {'b': 'Python', 'a': 5};  print D['a']
    
    gibt, analog zum Perl-Beispiel, 5 aus.

Operatoren

Perl

Perl besitzt sehr viele Operatoren, die zum großen Teil aus Shell-Sprachen und von C übernommen sind. Einige Operatoren sind "doppelt", damit sie sowohl für Zahlen als auch für Zeichenketten wie erwartet funktionieren. Perls Operatoren sind

    () [] {} <> -> ++ -- ** ! ~ \ =~ !~ * / % x + - . << >>
    -r -w -x -o -R -W -X -O -e -z -s -f -d -l -p -S -b -c -t
    -u -g -k -M -A -C
    < > <= >= lt gt le ge == != <=> eq ne cmp
    & | ^ && || .. ?:
    = **= += -= .= *= /= \%= x= &= |= ^= <<= >>= &&= ||=
    , => not and or xor

Python

  • Python besitzt deutlich weniger Operatoren, nämlich
        () [] {} ``  [:] . + - ~ ** * / % << >> & ^ |
        is in < <= > >= == <> != not and lambda or
    
    Seit Python 2.0 gibt es analog zu Perl außerdem die Operatoren
        += -= **= *= /= %= <<= >>= &= ^= |=
    
  • Andererseits muss man für viele der Aufgaben, die Perl mit seinen eingebauten Operatoren abdeckt, eingebaute oder Funktionen aus Modulen aufrufen, bspw.
        $datei_da = -e 'dateiname';  # Dateiexistenz in Perl
        datei_da  = os.path.exists( 'dateiname' )  # dito in Python
    
    Die am häufigsten benötigten Operatoren sind aber auch in Python leicht zugänglich, z. B. arithmetische und Vergleichsoperatoren.

Anweisungsfolgen

Perl

  • In Perl können Anweisungen "frei" über mehrere Zeilen verteilt werden. Zwischen Anweisungen stehen Semikola:
        @liste = ( 1, 3 ); push  # Kommentar: sinnloser Umbruch ;-)
            @liste, 7;  print $liste[ 2 ];
    
  • Anweisungen der selben logischen Ebene werden in geschweifte Klammern eingefasst:
        if( $a > 0 )
        {
            $b = 1;
            $c = 2;
        }
    

Python

  • 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

Perl

  • Perl kennt eine if-Anweisung, aber auch eine unless-Anweisung. Letztere entspricht einer if-Anweisung mit negierter Logik, bspw. ist
        if( $a > $b )
        {
            $a = $b;    # $a maximal so gross wie $b
        }
    
    dasselbe wie
        unless( $a <= $b )
        {
            $a = $b;
        }
    
  • Der if-Zweig kann mit elsif und else ergänzt werden.
        if( $a > $b )
        {
            print '$a ist groesser als $b.', "\n";
        }
        elsif( $a < $b )
        {
            print '$a ist kleiner als $b.', "\n";
        }
        else
        {
            print '$a ist gleich $b.', "\n";
        }
    
  • Soll eine einzelne Anweisung bedingt ausgeführt werden, können if oder unless nachgestellt werden.
        $n++  if( $a > $b );
    

Python

  • Python kennt kein unless und kein nachgestelltes if.
  • Das vorletzte Perl-Beispiel lässt sich folgendermaßen auf Python übertragen:
        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

Perl

  • In Perl gibt es while-Schleifen. Der folgende Code sammelt alle ganzen Zahlen von 0 bis 99 in einer Liste.
        @liste = ();
        $i = 0;
        while( $i < 100 )
        {
            push @liste, $i;
            $i++;
        }
    
  • Dasselbe kann man mit einer for-Schleife erreichen.
        @liste = ();
        for $i (0 .. 99)
        {
            push @liste, $i;
        }
    
  • Noch viel kürzer geht es mit einer impliziten Schleife.
        @liste = (0 .. 99);
    
  • In Perl kann man eine Schleife mit last "vorzeitig" abbrechen.
        $gefunden = 0;
        for $eintrag ( @eintraege )
        {
            if( $gesucht eq $eintrag )
            {
                $gefunden = 1;
                last;  # Liste nicht weiter durchsuchen
            }
        }
    

Python

  • In Python gibt es ebensolche Konstrukte. Die while-Schleife lautet
        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)
    
  • Auch die implizite Schleife hat eine Entsprechung.
        liste = range(100)
    
    range(100) erzeugt eine Liste aller ganzen Zahlen von 0 bis 99, nicht bis 100.
  • Python verwendet break zum "vorzeitigen" Verlassen von Schleifen.
        gefunden = 0
        for eintrag in eintraege:
            if gesucht == eintrag:
                gefunden = 1
                break
    

Anwendungsbeispiel

Es soll eine Datei eingelesen, zeilenweise sortiert und in eine Datei mit der zusätzlichen Endung '.sortiert' geschrieben werden.

Perl

In Perl kann man das - in Anlehnung an "normale" Programmiersprachen - so machen:

    #!/usr/bin/perl -w

    # Dateiname ermitteln
    $dateiname = $ARGV[0];  # der Skriptname steht in $0
    @zeilen = ();

    # Datei lesen
    open DATEI, "<$dateiname"  or
      die "$dateiname laesst sich nicht oeffnen\n";
    while( !eof DATEI )
    {
        $zeile = <DATEI>  or
          die "$dateiname ist nicht lesbar\n";
        push @zeilen, $zeile;
    }
    close DATEI;

    # sortieren
    @zeilen = sort @zeilen;
    $dateiname = $dateiname . '.sortiert';

    # Datei schreiben
    open DATEI, ">$dateiname"  or
      die "$dateiname laesst sich nicht oeffnen\n";

    for $zeile (@zeilen)
    {
        print DATEI $zeile  or
          die "$dateiname ist nicht schreibbar\n";
    }
    close DATEI  or  die "$dateiname ist nicht schreibbar\n";

Üblicher ist folgendes.

    #!/usr/bin/perl -w

    # Dateiname ermitteln
    $dateiname = shift;

    # Datei lesen
    open DATEI, "<$dateiname"  or
      die "$dateiname laesst sich nicht oeffnen\n";
    @zeilen = <DATEI>  or
      die "$dateiname ist nicht lesbar\n";
    close DATEI;

    # sortieren
    @zeilen = sort @zeilen;
    $dateiname .= '.sortiert';

    # Datei schreiben
    open DATEI, ">$dateiname"  or
      die "$dateiname laesst sich nicht oeffnen\n";
    print DATEI @zeilen  or
      die "$dateiname ist nicht schreibbar\n";
    close DATEI  or  die "$dateiname ist nicht schreibbar\n";

Python

In Python geht es ganz ähnlich.

    #!/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"

Unterprogramme

Perl

  • Unterprogramme werden in Perl mit dem Schlüsselwort sub definiert.
  • Der Funktionsrumpf wird in geschweifte Klammern geschrieben.
  • Argumente werden an die Funktion in der speziellen Liste @_ übergeben; sie tragen keine Namen.
  • Es können beliebige Perl-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 zuletzt ausgewertete Ausdruck.
  • Beim Aufruf eingebauter Funktionen können Klammern weggelassen werden. (Unter bestimmten Bedingungen (Verwendung von Prototypen) ist dies auch bei eigenen Funktionen möglich.)
  • Die folgende Funktion ermittelt den Index eines Zahlenwertes in einer Liste.
        sub index {
            ($gesucht, @eintraege) = @_;
            my $i;                         # potenzieller Index
            for $i (0 .. $#eintraege)
            {
                return $i  if( $eintraege[$i] == $gesucht );
            }
            undef;                         # nicht gefunden
        }
    
        print index( 3, (1, 2, 3, 4) );    # suche 3 in der Liste
    

Python

  • Unterprogramme werden in Python mit dem Schlüsselwort def 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 entspricht der oben aufgeführten Perl-Funktion:
        def index(gesucht, 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
    

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.
  • Sowohl die Perl- als auch die Python-Distributionen enthalten neben Interpreter und Dokumentation eine große Anzahl an Modulen, bspw. zur Textverarbeitung und zur einfachen Verwendung von Internet-Protokollen.
  • Wenn es nicht ausdrücklich anders definiert wird, muss bei Verwendung eines Befehls aus einem Modul im Hauptprogramm (oder einem anderen Modul) dieser Befehl explizit genannt werden (s. Beispiele unten).

Perl

Grundlagen

  • Moduldateien tragen die Endung pm (für "Perl module").
  • In Perl beginnt der Code einer Moduldatei mit der package-Anweisung.
  • Der zuletzt ausgewertete Ausdruck eines Moduls muss 1 (oder allgemeiner: ein "wahrer" Wert) sein, um dem Interpreter das erfolgreiche Laden des Moduls bekannt zu machen.
  • Zum Beispiel definiert das folgende Modul EinModul die Variablen $var1 und @var2 sowie eine Funktion quadrat.
        # EinModul.pm
        # Definiere das Modul "EinModul"
        package EinModul;
    
        $var1 = 1;
        @var2 = (2, 3);
    
        sub quadrat
        {
            my $x = shift;
            $x * $x;
        }
    
        1;
    
  • In andere Dateien wird das Modul durch die use-Anweisung geladen.
  • Namen des geladenen Moduls werden mit dem Modulnamen, gefolgt von zwei Doppelpunkten qualifiziert. Ein Symbol wie $ oder @ geht dabei dem Modulnamen voraus.
  • Hier wird das im vorherigen Beispiel definierte Modul verwendet.
        #!/usr/bin/perl
        # Hauptprogramm
    
        use EinModul;
    
        $test = $EinModul::var1;
        $test = EinModul::quadrat(7);
    

Exportieren von Namen

  • Perl erlaubt sowohl dem Modul als auch dem importierenden Programm eine Entscheidung, welche Namen im importierenden Programm ohne Qualifizierung (also z. B. $var1 statt $EinModul::var1) verwendbar sein sollen.
  • Auf der Modulebene kann das Exportieren nach folgendem Muster gesteuert werden. (Es gibt noch mehr Möglichkeiten, die wir hier nicht behandeln wollen.)
        package EinModul;
    
        require Exporter;
        @ISA = qw(Exporter);
    
        @EXPORT = qw($var1);
        @EXPORT_OK = qw($var1 @var2);
    
        # weiterer Code ...
    
        1;
    
    Dabei gibt @EXPORT an, welche Namen standardmäßig exportiert werden. @EXPORT_OK enthält die Namen, die exportiert (bzw. importiert) werden dürfen.
  • Auf der Ebene des importierenden Programms wird das Modul so benutzt:
        use EinModul;                       # importiere nur $var1
    
        use EinModul qw(@var2);             # importiere nur @var2
    
        use EinModul qw($var1 quadrat);     # Fehler
    
    Die erste Form importiert die Namen, die in @EXPORT angegeben wurden. Die zweite importiert nur die hier genannten Namen (bzw. versucht es, siehe letzte Zeile).

Python

Grundlagen

  • 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, ein Modul als solches zu kennzeichnen. Ein Modul unterscheidet sich von einem Programm nur durch die Verwendung, nicht durch speziellen Code.
  • Analog zum obigen Perl-Code ist das folgende Python-Modul.
        #!/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 = EinModul.quadrat(7)
    

Exportieren von Namen

  • Welche Namen eines Moduls in ein Programm importiert werden, wird üblicherweise nur vom importierenden Programm gesteuert und nicht vom Modul.
  • Namen eines Moduls können importiert werden, indem import zusammen mit from benutzt wird.
        from EinModul import var1           # importiere nur var1
    
        from EinModul import var1, var2     # importiere var1 und var2
    
        from EinModul import var1, quadrat  # erlaubt (keine Exportbeschränkung)
    
        from EinModul import *              # importiere (fast) alles
    
    Mit der letzten Form werden alle Namen importiert, die nicht mit _ beginnen.

Objektorientierte Programmierung

Allgemeines

  • Objekte bieten Variablen und Funktionen (Methoden), die auf diese Daten wirken. Zum Bespiel 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.

Perl

  • Eine Klasse in Perl ist ein Modul (genauer: ein package) mit einigen Erweiterungen.
  • Ein Konstruktor, new, erzeugt ein neues Objekt, eine Instanz der Klasse.
  • Der Konstruktor erzeugt die der neuen Instanz zugeordneten Daten, meist in Form einer assoziativen Liste. Das Schlüsselwort bless ordnet das Objekt der Klasse zu, die dem Konstruktor implizit als erstes Argument übergeben wird.
  • Methoden des Objekts erhalten eine Referenz auf das gerade bearbeitete Objekt implizit als erstes Argument.
  • Die spezielle Liste ISA (von "is a") enthält die Namen der Klassen, von denen die im Modul definierte Klasse abgeleitet ist.
  • Unser oben genanntes Beispiel in Perl-Code:
        # Ofen.pm
    
        package Ofen;
    
        sub new
        {
            my $class = shift;              # erstes - implizites - Argument
            my $self = {
              temperatur => 20,             # Raumtemperatur
              klappe_auf => 0,              # Klappe ist zu
              inhalt => undef };            # kein Inhalt
            bless $self, $class;            # Instanz wird "gesegnet"
        }
    
        sub klappe_oeffnen
        {
            my $self = shift;
            if( $self->{temperatur} > 20 )
            {
                print "Bitte vor dem Oeffnen der Klappe den Ofen abkuehlen!\n";
                return;
            }
            $self->{klappe_auf} = 1;
        }
    
        sub klappe_schliessen
        {
            my $self = shift;
            $self->{klappe_auf} = 0;
        }
    
        sub fuellen_mit
        {
            my $self = shift;
            if( ! $self->{klappe_auf} )
            {
                print "Bitte vor dem Fuellen die Klappe oeffnen!\n";
                return;
            }
            $self->{inhalt} = shift;
        }
    
        sub aufheizen
        {
            my $self = shift;
            if( $self->{klappe_auf} )
            {
                print "Bitte vor dem Aufheizen die Klappe schliessen!\n";
                return;
            }
            $self->{temperatur} = shift;    # Temperatur als Argument
        }
    
        sub abkuehlen
        {
            my $self = shift;
            $self->{temperatur} = 20;
        }
    
        1;
    
        # ----------------------------------------------------------------
        # Umluftherd.pm
    
        package Umluftherd;
    
        use Ofen;
    
        @ISA = qw(Ofen);                    # erhalte alle Variablen
                                            #  und Methoden von Ofen
        sub new
        {
            my $class = shift;
            my $self = new Ofen;
            $self->{umluft} = 0;            # Umluft aus
            bless $self, $class;
        }
    
        sub umluft_an
        {
            my $self = shift;
            $self->{umluft} = 1;
        }
    
        sub umluft_aus
        {
            my $self = shift;
            $self->{umluft} = 0;
        }
    
        1;
    
        # ----------------------------------------------------------------
        # ofentest.pl
    
        #!/usr/bin/env perl
    
        use Umluftherd;
    
        $herd = new Umluftherd;
        $herd->klappe_oeffnen;
        $herd->fuellen_mit('Teig');
        $herd->klappe_schliessen;
        $herd->umluft_an;
        $herd->aufheizen(250);
        sleep 60*60;                        # eine Stunde backen
        $herd->abkuehlen;
        $herd->umluft_aus;
    

Python

  • Eine Klasse in Python ist unabhängig von Modulen. Sie 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.
  • Auch bei Python erhalten Methoden 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.
  • Nach der Perl-Version folgt nun die Python-Variante des Beispiels.
        # ofenmod.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
    
    
        # ----------------------------------------------------------------
        # umluftherdmod.py
    
        import ofenmod
    
        class Umluftherd(ofenmod.Ofen):
            def __init__(self):
                ofenmod.Ofen.__init__(self)
                self.umluft = 0
    
            def umluft_an(self):
                self.umluft = 1
    
            def umluft_aus(self):
                self.umluft = 0
    
    
        # ----------------------------------------------------------------
        # ofentest.py
    
        #!/usr/bin/env python
    
        import umluftherdmod, time
    
        herd = umluftherdmod.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()
    

Sprachphilosophien

Perl

  • Einfache Aufgaben sollen mit wenig Aufwand gelöst werden können. In diesem Sinn ist in Perl eine kompakte Schreibweise wichtiger als die Lesbarkeit des Codes.
  • "There is more than one way to do it" ("TIMTOWTDI"), d. h. es gibt fast immer mehrere Wege, die jeweils selbe Aufgabe zu lösen. Man sieht das bspw. an den Alternativen if und unless oder an der folgenden Abwandlung des Suchalgorithmus aus dem Abschnitt über Schleifen.
        $gefunden = 0;
        for $eintrag (@eintraege)
        {
            $gefunden = 1, last  if( $gesucht eq $eintrag );
        }
    

Python

  • Programme sollen leicht schreib-, les- und wartbar sein.
  • Die Sprache soll sich erwartungsgemäß verhalten. Beispielsweise liefert
        L1 = [ 1, 2, [4, 5], 7 ]; L2 = L1[2]
    
    die Liste [4, 5] in L2, während in Perl
        @L1 = ( 1, 2, (4, 5), 7 ); @L2 = $L1[2];
    
    eine Liste mit dem einzigen Element 4 erzeugt. (Um die Wirkung des obigen Python-Codes zu erhalten, muss man in Perl
        @L1 = ( 1, 2, [4, 5], 7 ); @L2 = @{ $L1[2] };
    
    schreiben.)
  • Für ein Problem (von wenigen Codezeilen) sollte es eine - offensichtliche - Lösung geben. Tatsächlich gibt es i. Allg. auch in Python mehrere Möglichkeiten, aber normalerweise weniger als in Perl.

Bewertung

Vorteile von Perl gegenüber Python

  • Perl ist weiter verbreitet; es gibt eine umfangreichere Code-Sammlung (CPAN, Comprehensive Perl Archive Network).
  • Kurze Programme, vor allem solche zur Textmanipulation mit vielen regulären Ausdrücken (regular expressions), sind in Perl kompakter.
  • Perl-"Programme" für einfache Suchen-und-ersetzen-Aufgaben lassen sich leicht allein auf der Kommandozeile realisieren. Das folgende Beispiel ersetzt alle ../image/left.png in index.html durch image/left.png.
        perl -i.bak -pe's#\.\./image/left\.png#image/left.png#g' index.html
    

Vorteile von Python gegenüber Perl

  • Python ist leichter zu erlernen, zu lesen und zu warten.
  • Durch Ausnahmebehandlung wird die Abwicklung von Laufzeitfehlern sehr erleichtert.
  • Die Programmentwicklung in Python ist fast immer schneller, weil die Bedeutung des gerade geschriebenen Codes leichter erfassbar ist. Dadurch werden von vornherein weniger (nicht-triviale) Fehler gemacht und die benötigte Zeit zur Fehlersuche ist wesentlich geringer (vgl. die Ausführungen zum erwartungsgemäßen Verhalten).
  • Pythons Ansätze zur objektorientierten Programmierung sind konsequenter als bei Perl. Python erlaubt bspw. mehr als eine Instanzvariable und das Überladen von Operatoren, wodurch generischer Code leichter erstellt werden kann.

Empfehlungen

Gleich gute Eignung

Für diese Anwendungsfelder sind beide Sprachen - von ihrer "Ausstattung" her - etwa gleich gut geeignet:

  • CGI-Programmierung
  • andere Internet-Anwendungen (Emails abholen oder verschicken, HTML-Quellcode parsen oder erzeugen etc.)
  • "Tk-artige" Programme mit graphischer Oberfläche. Für Perl gibt es Perl/Tk, für Python Tkinter.
  • Perl und Python (Modul re) verstehen dieselbe Syntax von regulären Ausdrücken.

Kriterien für Perl

Folgende Kriterien sprechen für Perl:

  • Es ist bereits verhältnismäßig viel Perl-Code im Rahmen eines Projekts entstanden; ein Wechsel auf Python würde bewirken, dass ein großer Teil neu geschrieben werden muss.
  • Das Projekt hängt maßgeblich von Modulen ab, für die es keine Entsprechung in Python gibt und die nicht leicht selbst zu programmieren sind.
  • Es sollen nur kurze "Einwegskripte" erstellt werden, bei denen die Wartbarkeit unwichtig ist.
  • Alle an dem Projekt beteiligten Programmierer sind sehr vertraut mit Perl, aber nicht alle mit Python.
  • In einem Web-Projekt ist der Provider fest vorgegeben und unterstützt Python trotz Nachfrage nicht.

Kriterien für Python

Diese Kriterien sprechen besonders für Python:

  • An dem Projekt arbeitet nicht nur eine Person; der Code soll von verschiedenen Programmierern geschrieben und/oder gewartet werden.
  • Das Programm hängt von Python-Modulen ab, die es nicht für Perl gibt und die nicht leicht neu zu implementieren sind.
  • Der/die Programmierer arbeiten nicht "jeden Tag" an dem Projekt. In diesem Fall sind Fehler bei der Entwicklung mit Perl besonders häufig (Stichworte: Skalar- vs. Listenkontext, verschachtelte Datenstrukturen, Konstruktoren und Vererbung).
  • Der Pythoncode soll während der Entwicklung oder später zusammen mit Java verwendet werden. Mit JPython (Implementation von Python in Java) ist diese Verknüpfung besonders leicht.

Abschließende Bemerkungen

  • Faustregel: Wenn es nicht besondere Gründe gibt, Perl zu verwenden, sollte man ein Projekt mit Python in Angriff nehmen.
  • Für beide (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/perlpy_index.html