C2F: Higher-Order Functions erstellen

Ich kann Funktionen als Argumente für andere Funktionen verwenden und dadurch höherwertige Funktionen erstellen.

Lernziele

# Lernziel Beantwortet in
1 Ich kann eine Funktion schreiben, die eine andere Funktion als Parameter entgegennimmt und aufruft. 1. Funktion als Argument übergeben
2 Ich kann eine eigene Higher-Order Function implementieren (z.B. eine eigene apply-Funktion). 2. Eigene Higher-Order Function schreiben
3 Ich kann das Callback-Muster mit Higher-Order Functions umsetzen, um flexiblen, wiederverwendbaren Code zu schreiben. 3. Callback-Muster anwenden

1. Funktion als Argument übergeben

Eine Higher-Order Function ist eine Funktion, die als Parameter selbst eine andere Funktion entgegennimmt und diese aufruft, oder eine Funktion als Ergebnis liefert.

def apply_twice(func, value):
    # Erwartet eine Funktion als Argument und wendet diese zweimal an
    return func(func(value))

print(apply_twice(lambda x: x + 3, 7))   # 13  (7→10→13)
print(apply_twice(lambda x: x * 2, 5))   # 20  (5→10→20)

apply_twice ist eine Higher-Order Function, weil ihr Parameter func keine statische Variable ist, sondern selbst ein Verhalten darstellt. Welche exakte Logik ausgeführt wird, entscheidet sich erst beim Methodenaufruf.

Eingebaute Higher-Order Functions in Python

Python besitzt zahlreiche vordefinierte Higher-Order Functions für elegante Datentransformationen:

Funktion Callback-Art Anwendungsfall
map() Transformations-Funktion Jedes Element umwandeln
filter() Prüf-Funktion (Predicate) Elemente nach Kriterium filtern
sorted() Sortierschlüssel (key=) Sortierreihenfolge definieren
reduce() Aggregations-Funktion Alle Elemente cumulativ zusammenfassen

2. Eigene Higher-Order Function schreiben

Eigenes apply_to_all (wie map, aber selbst verfasst)

def apply_to_all(lst, func):
    result = []
    for item in lst:
        result.append(func(item))
    return result

numbers = [1, 2, 3, 4]

doubled = apply_to_all(numbers, lambda x: x * 2)  # [2, 4, 6, 8]
squared = apply_to_all(numbers, lambda x: x * x)  # [1, 4, 9, 16]
negated = apply_to_all(numbers, lambda x: -x)     # [-1, -2, -3, -4]

Dieselbe apply_to_all-Routine kann völlig unterschiedliche Transformationen durchführen, weil die konkrete Programm-Logik von aussen eingefügt wird (Dependency Injection).

Funktion zurückgeben: create_multiplier

def create_multiplier(factor):
    return lambda x: x * factor

doubler = create_multiplier(2)
tripler = create_multiplier(3)

print(doubler(5))  # 10
print(tripler(5))  # 15

Auch create_multiplier ist eine Higher-Order Function, weil sie eine Funktion-Referenz zurückgibt. Das zurückgegebene Lambda speichert den übergebenen factor (sog. Closure) dauerhaft.


3. Callback-Muster anwenden

Das Callback-Prinzip sieht vor, dass man eine Funktion übergibt, die zu einem bestimmten Zeitpunkt oder unter bestimmten Bedingungen ausgeführt wird. Das erhöht die Wiederverwendbarkeit und reduziert Code-Duplikation.

Beispiel: Listenverarbeitung mit Logging-Callback

def process_with_callback(items, filter_rule, on_match):
    result = []
    for item in items:
        # Erste Funktion wird als Filter-Test genutzt
        if filter_rule(item):
            # Zweite Funktion wird aufgerufen, wenn das Item den Filter erfüllt
            on_match(item)
            result.append(item)
    return result

numbers = [1, 2, 3, 4, 5, 6, 7, 8]

# Callback: Gefundene Elemente im Terminal melden
even_numbers = process_with_callback(
    numbers,
    lambda x: x % 2 == 0,
    lambda x: print(f"Gefunden: {x}")
)
# Konsolenausgabe:
# Gefunden: 2
# Gefunden: 4
# Gefunden: 6
# Gefunden: 8

Beispiel: Austauschbare Validierungs-Logik

def validate_all(inputs, rule):
    # Diese Funktion definiert nur das "wie", nicht das "was"
    return all(rule(item) for item in inputs)

emails = ["a@b.ch", "c@d.com", "e@f.org"]

all_have_at = validate_all(emails, lambda s: "@" in s)           # True     
all_are_swiss = validate_all(emails, lambda s: s.endswith(".ch"))  # False

Die eigentliche Validierungs-Logik (rule) wird komplett ausgelagert. Die Funktion validate_all bleibt völlig neutral und weiss nicht, welche spezifischen Anforderungen geprüft werden – sie fungiert nur als Wrapper für die Callback-Ausführung.


This site uses Just the Docs, a documentation theme for Jekyll.