Open Source im professionellen Einsatz
Linux-Magazin Online Artikel/
(c) Galyna Andrushko, 123rf.com

(c) Galyna Andrushko, 123rf.com

Funktionale Programmierung (2): Python funktional

Auf neuen Wegen

15.10.2009

Die meisten Entwickler verbinden Python mit dem objektorientierten Programmierstil. Doch die Sprache beschreitet vermehrt auch die Pfade der funktionalen Programmierung. Dieser Artikel zeigt, was Python in Sachen Closures, List Comprehension und Funktionen höherer Ordnung zu bieten hat.

763

Python nennt sich eine objektorientierte Programmiersprache. Das ist aber nur die halbe Wahrheit, denn als Multiparadigmen-Programmiersprache unterstützt sie insbesondere auch die funktionale Programmierung, und dies in immer mächtigerer Art und Weise. Nachdem sich die erste Folge dieser Reihe mit den Grundzügen der funktionale Programmierung beschäftigte, wird sich dieser Artikel den Techniken, Built-in-Funktionen und Bibliotheken rund ums funktionale Programmieren in Python widmen.

Python, zwar nicht als funktionale Sprache entworfen, nimmt doch immer mehr funktionale Charakteristiken an. Waren es anfangs nur First Class Functions, so fanden immer wieder neue funktionale Features Eingang in die Sprache:

  • Closures
  • anonyme Funktionen (Lambda-Funktionen)
  • Generatoren und Generator-Ausdrücke.
  • die klassischen Funktionen höherer Ordnung "map", "filter" und "reduce" Python
  • List Comprehension

Closures

Closures oder innere Funktionen sind Funktionen, die beim Aufruf ihren Aufrufkontext konservieren. Diese spezielle Funktionen mit Gedächtnis sind eine beliebte Technik, um Dekoratoren in Python zu implementieren (siehe Rainer Grimm, "Dekoratoren in Python": Linux-Magazin 06/09, S. 96). Insbesondere ermöglichen Closures, Funktionen zu definieren, die innere Funktionen auf Anfrage zurückgeben. Für diese inneren Funktionen werden in Python gerne Lambda-Funktionen verwendet, denn durch sie können Closures sehr kompakt umgesetzt werden.

Ein klassischer Anwendungsfall für Closures und Lambda-Funktionen zugleich ist die Funktion "makefilter" aus Listing 1, die bei jedem Aufruf einen neuen Filter erzeugt. Vor dem Verständnis der Funktion "makefilter" steht zuerst das Verständnis der zwei funktionalen Komponenten Closures und Lambda-Funktionen.

Das kleine Beispiel "addWith" (Abbildung 1) zeigt, wie der Wert "first" beim Aufruf von "addWith" im Scope der Funktion gebunden wird, sodass auf ihn lesend aus der inneren Funktion "innerFunction" zugegriffen werden kann.

Abbildung 1: Lesender Zugriff auf den äußeren Scope.

Leider ist die Umsetzung von Closures unter Python 2 sehr eingeschränkt, da sich der umgebene Scope aus der inneren Funktion nur lesend referenzieren lässt (Abbildung 1).

Den schreibenden Zugriff auf eine Variable "start" aus der inneren Funktion "memorizeCount" quittiert der Interpreter mit einer schwer verständlichen Fehlermeldung (Abbildung 2). Durch den schreibenden Zugriff auf die Variable "start" in dem Ausdruck "start+=1" wird eine neue Variable in deren Scope angelegt. Bevor die Variable "start" einen Wert besitzt, wird aber versucht, diesen zu lesen. Dieser Zugriff muss scheitern.

Abbildung 2: Der schreibende Zugriff auf den äußeren Scope scheitert in Python 2.*

Mit dem neuen Schlüsselwort "nonlocal" erlaubt Python 3.0 auf den äußeren, nicht lokalen Scope schreibend zuzugreifen. Damit ist ein Zähler schnell implementiert.

Abbildung 3: Schreibender Zugriff auf den äußeren Scope mit Python 3.*

Lambda-Funktionen

Das zweite Bausteinchen für das Verständnis der Filter-Funktion (Listing 1) fehlt noch. Was sind Lambda-Funktionen? Lambda-Funktionen oder auch anonyme Funktionen sind Funktionskörper ohne Namen. Diese nehmen in Python eine beliebige Anzahl von Argumenten an und führen einen Ausdruck aus - zugleich der Rückgabewert der Funktion.

Lambda-Funktionen werden gerne im Zusammenhang mit Funktionen höherer Ordnung verwendet. Die Funktion "makefilter" aus Listing 1 ist eine First Class Function, denn sie gibt eine Funktion zurück, genauer die Lambda-Funktion "lambda s,a=allchars,d=delchars: s.translate(a, d)".

Listing 1: Filter-Funktion

def makefilter(keep):
    """ Return a function that takes a string and returns a copy of that
        string consisting only of the characters in 'keep'.
    """
    import string
    # make a string of all chars, and one of all those NOT in 'keep'
    allchars = string.maketrans('', '')
    delchars = ''.join([c for c in allchars if c not in keep])
    # return the function
    return lambda s,a=allchars,d=delchars: s.translate(a,d)

Aber nun von Anfang an: Die Funktion "makefilter" erzeugt bei jedem Aufruf der Funktion einen Filter, der nur die Buchstaben aus "keep" passieren lässt. Der Schlüssel zum Verständnis dieses Filters ist die Funktion "translate" aus der String-Bibliothek. "s.translate(a,d)" übersetzt einerseits alle Zeichen des Strings "s" entsprechend der Übersetzungstabelle "a" und löscht andererseits die Zeichen, die sich in "d" befinden. Nun ist die Übersetzungstabelle "a" in diesem konkreten Fall "string.maketrans('','')" die Identität und "d" das Komplement zu "keep". Das einzige fehlende Argument für die Lambda-Funktion "lambda s,a=allchars,d=delchars: s.translate(a,d)" ist der zu filternde String "s". Dieser String ist das Argument für die Filter-Funktion (Abbildung 4).

Abbildung 4: Die Filter-Funktion im Einsatz.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Online-Artikel: Funktionale Programmierung in Python

    Python gilt vielen als objektorientierte Sprache, doch unterstützt es auch andere Paradigmen. Rainer Grimm demonstriert in seinem kostenlosen Online-Artikel das funktionale Programmieren in Python.

  • Funktionale Programmierung (1): Grundzüge

    Ob Microsofts F# oder neue Features in C++, Java und Python: Der funktionale Programmierstil macht wieder Schlagzeilen. Mit diesem Online-Artikel beginnt Linux-Magazin Online eine kleine Reihe zur funktionalen Programmierung. In der ersten Folge beschreibt unser Autor Rainer Grimm die Grundzüge dieses Programmierparadigmas. Kommende Folgen widmen sich der funktionalen Programmierung in Python und dem Framework MapReduce von Google.

  • C++11

    Lambda-Funktionen sind die praktischen Helfer der Sprache C++11. Schon nach kurzer Zeit möchte kein C++-Entwickler sie missen, denn mit ihnen ist ein Algorithmus rasch und ohne Umschweife formuliert. Außerdem darf er sie wie Objekte behandeln.

  • Im Zeichen der Drei

    Mit Python 3.0 hat Sprachschöpfer Guido van Rossum seine Skriptsprache ausgemistet. Nun bringt Python 3.1 noch die Performance in Ordnung. Was muss ein Programmierer beim Umstieg von Python 2.x wissen? Wie und wann portiert er bestehende Skripte auf die neue Sprachversion?

comments powered by Disqus

Ausgabe 09/2016

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.