29. List Comprehensions

Die list comprehension hat Python aus der funktionalen Programmiersprache Haskell. Die Idee ist, eine Liste quasi algorithmisch zu beschreiben, angelehnt an die mathematische Notation

{upper (s)|s ∈ L} :

>>> l = ["e", "ba", "guU"]
>>> [s.upper() for s in l]
['E', 'BA', 'GUU']

Die Liste wird also innerhalb von eckigen Klammern durch eine Iteration und einen Ausdruck beschrieben. Bei Bedarf kann noch eine Selektion dazu kommen:

>>> [str(b) for b in range(10) if b>4]
['5', '6', '7', '8', '9']

Man kann auch mehrfach iterieren, es ist aber trotzdem nur eine Bedingung zugelassen:

>>> [(a,b) for a in range(10)
   for b in range(10) if a==b]
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5),
(6, 6), (7, 7), (8, 8), (9, 9)]

Zunächst sieht das nach syntactic sugar aus (also wie Spracheigenschaft, die recht einfach auch mit anderen, sozusagen hässlicheren Sprachelementen nachgebildet werden kann).

Tatsächlich kommen list comprehensions aber aus dem funktionalen Programmieren, einer Technik, die ohne Zuweisungen auskommt – in ihr ist ein Programm einfach eine fortgesetzte Anwendung von Funktionen auf die Ergebnisse anderer Funktionen.

Entscheidend dabei ist der Verzicht auf Seiteneffekte, d.h. Änderungen am Zustand des Rechners, die nicht durch die Argumente der Funktion und ihren Rückgabewert beschrieben sind. Pythons list comprehensions sind nach dieser Definition nicht exakt funktional, weil sie die Bindung (mindestens) eines Namens bewirken, nämlich der ”Schleifenvariablen„:

>>> [s.lower() for s in "tokenize me".split()]
['tokenize', 'me']
>>> s
'me'

Vorteil: Rein funktionale Programme lassen sich mit dem λ-Kalkül untersuchen. Für imperative Programme (also Abfolgen von Anweisungen) ist der weit kompliziertere Hoare-Kalkül nötig.

Trotz dieser Anmerkung ist es natürlich nicht schwierig, die List Comprehension durch imperative Methoden nachzubauen. So entspricht etwa

l = [ expression for expr in sequence1
        for expr2 in sequence2 ...
        for exprN in sequenceN
        if condition]

genau

l = []
for expr1 in sequence1:
  for expr2 in sequence2:
  ...
    for exprN in sequenceN:
      if (condition):
        l.append(expression)

Übungen zu diesem Abschnitt

Ihr solltet euch wenigstens an den rötlich unterlegten Aufgaben versuchen

(1)

Angenommen, ein Algorithmus verlange nach der Menge aller Paare natürlicher Zahlen (die Null soll da nicht dabei sein) kleiner 10, bei denen die erste durch die zweite ohne Rest teilbar ist. Wie würdet ihr das mit list comprehensions formulieren? Gießt das in eine Funktion, die ein Argument nimmt, um von der hartkodierten 10 wegzukommen.

(2)

Formuliert die Funktion zur Wandlung einer Datei mit Attribut-Wert-Paaren in ein Dictionary mit list comprehensions um.


Markus Demleitner

Copyright Notice