# Python Lambda: Anonyme Funktionen in Python

Lambda-Funktionen existieren seit Python 1.0 als **Mittel für funktionale Programmierung**. Heutzutage ist ihr Nutzen weitgehend durch andere Techniken ersetzt worden. Jedoch gibt es weiterhin einige spezialisierte Einsatzgebiete, die versierte Python-Programmierer und -Programmiererinnen kennen sollten.

## Was sind Lambda-Funktionen in Python?

Unter dem Begriff **„Lambda-Funktion“ versteht man in Python eine anonyme Funktion**. Zum Erzeugen einer Lambda-Funktion kommt in Python das `lambda`-Schlüsselwort zum Einsatz. Ein Lambda-Ausdruck besteht aus dem `lambda`-Schlüsselwort, gefolgt von einer Liste von Argumenten, einem Doppelpunkt und einem einzelnen Ausdruck („Expression“). Der Ausdruck wird beim Aufruf der Lambda-Funktion mit den Argumenten versehen und evaluiert:

```none
lambda argument: expression
```

Funktionen sind ein grundlegendes Sprachkonstrukt fast aller Programmiersprachen und stellen die kleinste wiederverwendbare Einheit von Code dar. Üblicherweise werden **Funktionen in Python mit dem `def`-Schlüsselwort definiert**. Wir zeigen beispielshalber die Quadratfunktion, die eine Zahl mit sich selbst multipliziert:

```python
# Define square function
def square(num):
    return num * num
# Show that it works
assert square(9) == 81
```

Neben dem bekannten Weg, Funktionen in Python per `def`-Schlüsselwort zu definieren, kennt die Sprache die „Lambdas“. Das sind kurze, **anonyme (sprich: unbenannte) Funktionen, die einen Ausdruck mit Parametern definieren**. Lambdas lassen sich überall einsetzen, wo eine Funktion erwartet wird, oder per Zuweisung an einen Namen binden. Hier der zur Quadratfunktion äquivalente Lambda-Ausdruck:

```python
# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81
```

Hinweis Der Term „Lambda-Funktion“ bezeichnet in Python eine mit dem Lambda-Schlüsselwort erzeugte Funktion. Lambda ist nicht etwa der Name einer Funktion und es handelt sich auch nicht um einen der Python-Operatoren.

### Was ist der Unterschied zwischen lambda und def?

Zunächst scheint es seltsam, dass Python mit `lambda` und `def` zwei Wege kennt, Funktionen zu erzeugen. Dabei ist `lambda` **kein eigenes Feature, sondern lediglich eine andere Schreibweise**, um kurze Funktionen lokal zu erzeugen. Jede Funktion, die mit `lambda` erzeugt wurde, lässt sich nämlich auch via `def` erzeugen. Jedoch ist dies andersherum nicht der Fall.

Auf syntaktischer Ebene sind sowohl `lambda` als auch `def` Schlüsselwörter. Ein Unterschied zwischen den beiden liegt in Python’s **strikter Trennung von Anweisung („Statement“) und Ausdruck („Expression“)**. Kurz gesagt sind Anweisungen Schritte in der Ausführung von Code, während Ausdrücke zu einem Wert evaluiert werden.

Mit `def` beginnt eine **Anweisung (spezifisch ein „Compound Statement“), die weitere Anweisungen enthält**. Innerhalb der `def`-Anweisung – und nur dort – dürfen `return`-Anweisungen auftauchen. Beim Aufruf der mit `def` definierten Funktion liefert eine `return`-Anweisung einen Wert zurück.

Im Gegensatz zur `def`-Anweisung **beginnt `lambda` einen Ausdruck, der keine Anweisungen enthalten darf**. Der Lambda-Ausdruck nimmt ein oder mehrere Argumente entgegen und liefert eine anonyme Funktion zurück. Wird die erzeugte Lambda-Funktion aufgerufen, wird der enthaltene Ausdruck mit den übergebenen Argumenten evaluiert und zurückgegeben.

### Was sind die Beschränkungen von Python’s Lambda-Ausdrücken?

Python schränkt den Nutzen von Lambda-Funktionen gezielt ein, da es in der Regel **besser ist, Funktionen zu benennen**. Dies zwingt Programmierer und Programmiererinnen, über den Sinn der Funktion nachzudenken und Teile klar voneinander abzugrenzen.

Anders als der Körper einer via `def`-Schlüsselwort definierten Funktion, können Lambdas keine Anweisungen enthalten. Es ist daher **nicht möglich, `if`, `for`, etc. innerhalb einer Lambda-Funktion einzusetzen**. Auch das Auslösen einer Exception ist nicht möglich, da dafür die `raise`-Anweisung benötigt wird.

Lambda-Funktionen in Python dürfen nur einen einzelnen Ausdruck enthalten, der beim Aufruf evaluiert wird. Innerhalb des Lambda-Ausdrucks können **keine Typ-Annotationen verwendet werden**. Heutzutage kommen für die meisten Anwendungsfälle von Lambda-Funktionen in Python andere Techniken zum Einsatz. Vor Allem die Comprehensions sind hierbei zu nennen.

## Wozu werden Lambda-Funktionen in Python eingesetzt?

Generell **entstammen Lambdas der funktionalen Programmierung**. In manchen Sprachen, wie JavaScript, werden anonyme Funktionen vielfach eingesetzt, ohne dass dafür ein besonderes Schlüsselwort zum Einsatz käme. In Python dienen Lambda-Ausdrücke dazu, kleine Funktionen lokal ohne großes Drumherum zu erzeugen. Wir zeigen die nützlichsten Anwendungsfälle.

### Funktionen höherer Ordnung in Python mit Lambdas bestücken

Lambdas werden oft im Zusammenhang mit **Funktionen höherer Ordnung wie `map()`, `filter()` und `reduce()`** verwendet. Mit deren Hilfe lassen sich die Elemente eines „Iterable“ ohne Einsatz von Schleifen transformieren. Als Funktionen höherer Ordnung (auf Englisch „higher-order functions“) werden Funktionen bezeichnet, die als Parameter Funktionen entgegennehmen, oder eine Funktion zurückgeben.

Die `map()`-Funktion nimmt als Parameter eine Funktion und ein Iterable entgegen und führt die Funktion für jedes Element des Iterable aus. Betrachten wir das Problem, Quadratzahlen zu erzeugen: Wir nutzen die `map()`-Funktion und **übergeben einen Lambda-Ausdruck als Argument, der die Quadratfunktion erzeugt**. Mit `map()` wird die Quadratfunktion auf jedes Element der Liste angewandt:

```python
nums = [3, 5, 7]
# Square numbers using using `map()` and `lambda`
squares = map(lambda num: num ** 2, nums)
# Show that it works
assert list(squares) == [9, 25, 49]
```

Hinweis Seit Python 3.0 geben die `map()`- und `filter()`-Funktionen ein Iterable statt einer Liste zurück. Wir nutzen innerhalb der `assert`-Anweisung einen `list()`-Aufruf, um das Iterable in eine Liste zu entpacken.

Mit List-Comprehensions existiert heutzutage ein **moderner, präferierter Ansatz zum Verarbeiten von Iterables**. Anstatt auf `map()` zurückzugreifen und eine Lambda-Funktion zu erzeugen, beschreiben wir die Operation direkt:

```python
nums = [3, 5, 7]
# Square numbers using list comprehension
squares = [num ** 2 for num in nums]
# Show that it works
assert squares == [9, 25, 49]
```

Mit der `filter()`-Funktion lassen sich die **Elemente eines Iterable filtern**. Wir erweitern unser Beispiel, sodass nur gerade Quadratzahlen erzeugt werden:

```python
# List of numbers 1–4
nums = [1, 2, 3, 4]
# Square each number
squares = list(map(lambda num: num ** 2, nums))
# Filter out the even squares
even_squares = filter(lambda square: square % 2 == 0, squares)
# Show that it works
assert list(even_squares) == [4, 16]
```

Wir zeigen wiederum den modernen, bevorzugten Ansatz, per List-Comprehension **dasselbe Ergebnis ohne Einsatz von Lambdas und higher-order Functions** zu generieren. Dabei nutzen wir den `if`-Teil der Comprehension, um aus den erzeugten Quadratzahlen die geraden herauszufiltern:

```python
# List of numbers 1–4 squared
squares = [num ** 2 for num in range(1, 5)]
# Filter out the even squares
even_squares = [square for square in squares if square % 2 == 0]
# Show that it works
assert even_squares == [4, 16]
```

Hinweis Python’s `reduce()`-Funktion ist seit Python 3.0 nicht mehr Teil der Standard-Bibliothek. Sie wurde in das `functools`-Modul ausgelagert.

### Schlüssel-Funktionen in Python als Lambdas realisieren

Comprehensions haben den Einsatz der klassischen higher-order Functions `map()` und `filter()` in Python größtenteils abgelöst. Mit den sog. „Key-Functions“, zu Deutsch „Schlüssel-Funktionen“ besteht jedoch ein **Anwendungsszenario, in dem Lambdas ihre Stärken voll ausspielen**.

Die Python-Vergleichsfunktionen `sorted()`, `min()` und `max()` operieren auf Iterables. Beim Aufruf wird **jedes Element des Iterable einem Vergleich unterzogen**. Die drei Funktionen nehmen allesamt eine Schlüssel-Funktion als optionalen `key`-Parameter entgegen. Die Schlüssel-Funktion wird für jedes Element aufgerufen und liefert einen Schlüssel-Wert für die Vergleichsoperation.

Betrachen wir als Beispiel, das folgende Problem. Uns liegt ein Ordner mit Bild-Dateien vor, deren Namen in einer Python-Liste abgebildet sind. **Wir möchten die Liste sortieren**. Die Dateinamen beginnen alle mit `img`, gefolgt von einer Nummerierung:

```python
# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']
```

Nutzen wir Python’s `sorted()`-Funktion, **kommt die sog. „lexikographische Ordnung“ zum Einsatz**. Das bedeutet, dass aufeinander folgende Ziffern als einzelne Zahlen behandelt werden. So werden die Nummern `['1', '2', '100']` in die Reihenfolge `['1', '100', '2']` gebracht. Das Ergebnis entspricht nicht unseren Erwartungen:

```python
# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']
```

Um die Sortierung unseren Wünschen entsprechend zu gestalten, übergeben wir einen **`lambda`-Ausdruck, der eine Schlüssel-Funktion erzeugt**. Die Schlüssel-Funktion extrahiert den numerischen Teil eines Dateinamens, der von `sorted()` als Schlüssel verwendet wird:

```python
# Extract numeric component and sort as integers
sorted_image = sorted(images, key=lambda name: int(name[3:]))
# Show that it works
assert sorted_image == ['img1', 'img2', 'img3', 'img22', 'img30', 'img100']
```

Die Schlüssel-Funktion wird nur lokal und nur einmalig verwendet. Es ist unnötig, dafür extra eine benannte Funktion zu definieren. **Lambdas sind daher das geeignete Mittel zum Erzeugen von Schlüssel-Funktionen**. Betrachten wir zwei weitere Beispiele.

Neben `sorted()` nehmen die eingebauten Python-Funktionen `min()` und `max()` eine optionale Schlüssel-Funktion entgegen. Die Funktionen finden das kleinste bzw. größte Element einer Liste oder sonstigem Iterable. **Was genau das kleinste bzw. größte Element ausmacht, ist Definitionssache** und lässt sich über die Schlüsselfunktion festlegen.

Bei Listen einfacher Werte, beispielsweise einer Liste von Zahlen, ist **klar, was mit „kleinstem“ bzw. „größtem“ Element gemeint ist**. Hier benötigen wir keine spezielle Schlüssel-Funktion:

```python
nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69
```

Hinweis Wird keine Schlüssel-Funktion übergeben, kommt implizit die Identitäts-Funktion `f(x) = x` zum Einsatz. Diese lässt sich leicht als Python-Lambda mit `lambda x: x` definieren.

Was jedoch, wenn die Elemente eines Iterable jeweils mehrere Daten umfassen? Stellen wir uns eine List von Dicts vor, die Personen mit Name und Alter repräsentieren. Nach welchem Kriterium **sollen `min()` und `max()` entscheiden, welches Element am kleinsten bzw. größten ist**? Genau dafür kommt die Schlüssel-Funktion zum Einsatz.

Zum Veranschaulichen, **wie Schlüssel-Funktionen funktionieren, benötigen wir Beispiel-Daten**. Wir erzeugen eine Funktion `Person()`, die als Konstruktor dient:

```python
# Constructor function for dict representing a person
def Person(name, age):
    return {'name': name, 'age': age}
# Check that it works as expected
assert Person('Jim', 42) == {'name': 'Jim', 'age': 42}
```

Mithilfe unserer Konstruktor-Funktion **erzeugen wir eine Liste von Personen**:

```python
# Create list of people
people = [Person('Jim', 42), Person('Jack', 51), Person('John', 69)]
```

Im Anschluss finden wir die älteste Person via `max()`-Aufruf. Dabei **erzeugen wir per Lambda-Ausdruck eine Schlüssel-Funktion**, die ein Person-Dict entgegennimmt und daraus das Alter als Vergleichselement extrahiert:

```python
# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)
```

Der Ansatz funktioniert genau so für die `min()`-Funktion. Hier **definieren wir die Schlüssel-Funktion außerhalb des `min()`-Aufrufs**, wobei wir wiederum einen Lambda-Ausdruck nutzen. Dies verbessert die Lesbarkeit und lohnt sich, wenn die Schlüsselfunktion mehrfach lokal Verwendung findet:

```python
# Define key function to compare people by age
by_age = lambda person: person['age']
# Find the youngest person
youngest = min(people, key=by_age)
# Check that it works
assert youngest == Person('Jim', 42)
```

### Closures mit Python Lambdas erzeugen

Ein weiterer **Einsatzort für Python Lambdas liegt im Definieren sog. „Closures“**. Dabei handelt es sich um Funktionen, die von anderen Funktionen erzeugt werden und dabei einen Wert speichern. Mit Closures lassen sich beispielsweise Familien ähnlicher Funktionen erstellen. Wir zeigen das geläufige Beispiel, Potenzfunktionen zu erzeugen.

Potenzfunktionen nehmen ein Argument entgegen und potenzieren dieses. Bekannte Beispiele sind die Quadratfunktion `f(x) = x ^ 2` und die kubische Funktion `f(x) = x ^ 3`. Mittels einer Konstruktor-Funktion lassen sich beliebige Potenzfunktionen als Closures erzeugen. Wir nutzen einen Lambda-Ausdruck und sparen uns damit das definieren einer inneren benannten Funktion:

```python
# Define constructor function for power functions
def power(n):
    return lambda num: num ** n
# Create square and cubic functions as closures
square = power(2)
cubic = power(3)
# Show that it works
assert square(10) == 100
assert cubic(10) == 1000
```

### Immediately Invoked Function Expression (IIFE) mit Python Lambdas

Bei IIFE, ausgesprochen „iffy“ handelt es sich um ein **bekanntes Muster in JavaScript**. Dabei wird eine anonyme Funktion definiert und sofort ausgeführt.

Wenn auch durch die Beschränkung **in Python wenig nützlich, lassen sich Lambdas als IIFEs verwenden**. Wir benötigen lediglich Klammern um den Lambda-Ausdruck herum:

```python
(lambda num: num * num)
```

Sowie ein weiteres Paar Klammern, welche das oder die Argumente enthält:

```python
assert (lambda num: num * num)(3) == 9
```


This is a markdown version of: [https://www.ionos.com/de-ch/digitalguide/websites/web-entwicklung/lambda-funktionen-in-python/](https://www.ionos.com/de-ch/digitalguide/websites/web-entwicklung/lambda-funktionen-in-python/) for AI/LLM consumption.