Lambda-Funk­tio­nen gibt es bereits seit Python 1.0 als Werkzeug für die funk­tio­na­le Pro­gram­mie­rung. Heut­zu­ta­ge wurden sie in vielen Bereichen durch modernere Techniken ersetzt. Dennoch exis­tie­ren spe­zi­fi­sche Ein­satz­ge­bie­te, die erfahrene Python-Ent­wick­ler:innen kennen sollten.

Was sind Lambda-Funk­tio­nen in Python?

Hinter dem Begriff „Lambda-Funktion“ verbirgt sich in Python eine anonyme Funktion. Um eine solche zu erstellen, nutzt du das lambda-Schlüs­sel­wort. Ein Lambda-Ausdruck setzt sich aus diesem lambda-Key-Word, einer Liste von Ar­gu­men­ten, einem Dop­pel­punkt sowie einem einzelnen Ausdruck („Ex­pres­si­on“) zusammen. Dieser Ausdruck wird beim Aufruf mit den ent­spre­chen­den Ar­gu­men­ten ver­ar­bei­tet:

lambda argument: expression

Funk­tio­nen bilden das Fundament fast jeder Pro­gram­mier­spra­che und sind die kleinsten Bausteine für wie­der­ver­wend­ba­ren Code. Nor­ma­ler­wei­se werden Funk­tio­nen in Python mit dem def-Schlüs­sel­wort definiert. Als Beispiel dient hier die Qua­drat­funk­ti­on, die eine Zahl mit sich selbst mul­ti­pli­ziert:

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

Neben der klas­si­schen De­fi­ni­ti­on via def bietet Python eben auch die „Lambdas“. Das sind kompakte, anonyme (also namenlose) Funk­tio­nen für Ausdrücke mit Pa­ra­me­tern. Du kannst Lambdas überall dort einsetzen, wo eine Funktion verlangt wird, oder sie an einen Va­ria­blen­na­men binden. Hier siehst du die Qua­drat­funk­ti­on als Lambda-Ausdruck:

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

Was un­ter­schei­det lambda von def?

Es mag un­ge­wöhn­lich wirken, dass Python mit lambda und def zwei Wege zur Funk­ti­ons­er­stel­lung bietet. Tat­säch­lich ist lambda kein ei­gen­stän­di­ges Feature, sondern eine al­ter­na­ti­ve Schreib­wei­se, um kurze Funk­tio­nen direkt vor Ort zu erstellen. Jede lambda-Funktion lässt sich auch mit def umsetzen – umgekehrt gilt das jedoch nicht immer.

Rein syn­tak­tisch sind beides Schlüs­sel­wör­ter. Ein we­sent­li­cher Un­ter­schied liegt in Pythons klarer Trennung zwischen Anweisung („Statement“) und Ausdruck („Ex­pres­si­on“). Ver­ein­facht gesagt steuern An­wei­sun­gen den Pro­gramm­ab­lauf, während Ausdrücke einen konkreten Wert liefern.

Mit def startest du eine Anweisung (ein „Compound Statement“), die weitere Befehle enthalten kann. Nur innerhalb dieser def-Struktur dürfen return-An­wei­sun­gen stehen, um beim Funk­ti­ons­auf­ruf einen Wert zu­rück­zu­ge­ben.

Im Gegensatz dazu leitet lambda einen Ausdruck ein, der keinerlei An­wei­sun­gen enthalten darf. Der Lambda-Ausdruck nimmt Argumente an und gibt eine anonyme Funktion zurück. Sobald diese auf­ge­ru­fen wird, berechnet das Programm den ent­hal­te­nen Ausdruck mit den Werten und liefert das Ergebnis.

Welche Grenzen haben Python-Lambda-Ausdrücke?

world4you empfiehlt, Funk­tio­nen primär zu benennen, da dies die Les­bar­keit erhöht – Python schränkt Lambdas daher bewusst ein. Das zwingt dich dazu, die Logik deines Codes klarer zu struk­tu­rie­ren.

Im Vergleich zu Funk­tio­nen via def können Lambdas keine An­wei­sun­gen ausführen. Daher lassen sich Elemente wie if oder for nicht innerhalb einer Lambda-Funktion nutzen. Auch das gezielte Auslösen von Fehlern via raise ist hier nicht möglich.

Ein Lambda darf nur einen einzigen Ausdruck enthalten. Zudem sind keine Typ-An­no­ta­tio­nen erlaubt. In der modernen Python-Ent­wick­lung greift man für viele frühere Lambda-Szenarien lieber zu anderen Lösungen, allen voran den Com­pre­hen­si­ons.

Wann kommen Lambda-Funk­tio­nen in Python zum Einsatz?

Grund­sätz­lich stammen Lambdas aus der Welt der funk­tio­na­len Pro­gram­mie­rung. Während anonyme Funk­tio­nen in Sprachen wie Ja­va­Script all­ge­gen­wär­tig sind, nutzt du sie in Python vor allem für kleine, lokale Aufgaben. Wir haben die gän­gigs­ten Szenarien für dich zu­sam­men­ge­fasst.

Lambdas in Funk­tio­nen höherer Ordnung nutzen

Häufig triffst du Lambdas im Mix mit Funk­tio­nen höherer Ordnung wie map(), filter() oder reduce() an. Damit be­ar­bei­test du die Inhalte eines „Iterable“, ohne klas­si­sche Schleifen zu schreiben. Solche „higher-order functions“ zeichnen sich dadurch aus, dass sie Funk­tio­nen als Parameter annehmen oder selbst eine Funktion ausgeben.

Die map()-Funktion kom­bi­niert eine Funktion mit einem Iterable und wendet erstere auf jedes Element an. Wenn wir etwa Qua­drat­zah­len berechnen wollen, nutzen wir map() und übergeben einen Lambda-Ausdruck für die Qua­drie­rung. So wird die Operation auf die gesamte Liste an­ge­wen­det:

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]
python
Hinweis

Seit Python 3.0 liefern map() und filter() ein Iterable statt einer direkten Liste. Mit dem list()-Befehl wandeln wir dieses Ergebnis in eine druckbare Liste um.

Heute gilt die List-Com­pre­hen­si­on als mo­der­ne­rer Weg, um Iterables zu ver­ar­bei­ten. Statt map() und Lambda zu mischen, be­schrei­ben wir den Vorgang direkt:

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]
python

Mit filter() kannst du Inhalte eines Iterable filtern. Hier im Beispiel lassen wir nur gerade Qua­drat­zah­len zu:

# 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]
python

Auch hier ist die List-Com­pre­hen­si­on meist die bessere Wahl, um ohne Lambdas zum selben Ziel zu kommen. Wir nutzen den if-Teil, um die ungeraden Zahlen direkt aus­zu­sor­tie­ren:

# 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]
python
Hinweis

Pythons reduce()-Funktion gehört seit Version 3.0 nicht mehr zum Standard-Umfang, sondern befindet sich im functools-Modul.

Lambdas als Schlüssel-Funk­tio­nen einsetzen

Obwohl Com­pre­hen­si­ons viele Aufgaben über­nom­men haben, gibt es einen Bereich, in dem Lambdas glänzen: die so­ge­nann­ten „Key-Functions“ oder Schlüssel-Funk­tio­nen.

Ver­gleichs­funk­tio­nen wie sorted(), min() und max() arbeiten mit Iterables und ver­glei­chen deren Elemente. Über den op­tio­na­len key-Parameter kannst du eine Logik de­fi­nie­ren, die für jedes Element den maß­geb­li­chen Ver­gleichs­wert bestimmt.

Stell dir vor, du hast eine Liste mit Da­tei­na­men von Bildern, die du sortieren willst. Alle beginnen mit img, gefolgt von einer Nummer:

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

Nutzt du die Standard-Funktion sorted(), greift die le­xi­ko­gra­phi­sche Sor­tie­rung. Das führt dazu, dass Ziffern einzeln bewertet werden und etwa ['1', '100', '2'] vor ['1', '2', '100'] landet. Das Ergebnis ist meist nicht das, was du ei­gent­lich willst:

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

Um die Liste korrekt zu sortieren, nutzen wir einen lambda-Ausdruck als Schlüssel-Funktion. Dieser ex­tra­hiert den Zah­len­wert aus dem Namen, damit sorted() richtig sortieren kann:

# 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']
python

Da diese Logik oft nur an einer Stelle gebraucht wird, ist eine extra de­fi­nier­te Funktion meist über­flüs­sig. Lambdas sind hier das perfekte Werkzeug. Schauen wir uns weitere Beispiele an.

Auch min() und max() ak­zep­tie­ren solche Schlüssel-Funk­tio­nen, um das kleinste oder größte Element zu finden. Was genau als „klein“ oder „groß“ gilt, ent­schei­dest du über diese Funktion.

Bei einfachen Zah­len­lis­ten ist die De­fi­ni­ti­on von „Minimum“ und „Maximum“ eindeutig. Hier ist kein Extra-Aufwand nötig:

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

Ohne explizite Angabe nutzt Python die Iden­ti­täts-Funktion f(x) = x, was einem einfachen Lambda wie lambda x: x ent­spricht.

Kom­pli­zier­ter wird es bei kom­ple­xe­ren Daten, etwa einer Liste von Dicts mit Namen und Alter. Wonach sollen min() und max() hier bewerten? Hier kommt wieder die Schlüssel-Funktion ins Spiel.

Zuerst brauchen wir Bei­spiel­da­ten. Wir de­fi­nie­ren eine Funktion Person() als Kon­struk­tor:

# 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}
python

Damit erstellen wir eine Per­so­nen­lis­te:

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

Um nun die älteste Person zu finden, nutzen wir max() und ge­ne­rie­ren per Lambda eine Funktion, die gezielt das Alter aus den Dicts für den Vergleich her­aus­zieht:

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

Das klappt analog für min(). Falls du die Logik mehrfach an einer Stelle benötigst, kannst du das Lambda auch vorab einer Variablen zuweisen, um den Code über­sicht­li­cher zu halten:

# 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)
python

Closures mit Python-Lambdas erstellen

Ein weiteres Ein­satz­feld für Lambdas sind so­ge­nann­te „Closures“. Das sind Funk­tio­nen, die von anderen Funk­tio­nen erstellt werden und dabei bestimmte Werte „ein­schlie­ßen“ (speichern). So erstellst du effizient ganze Funk­ti­ons­fa­mi­li­en, wie etwa Po­tenz­funk­tio­nen. Mit einem Lambda sparst du dir die De­fi­ni­ti­on einer inneren Funktion:

# 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
python

Im­me­dia­te­ly Invoked Function Ex­pres­si­on (IIFE)

Das IIFE-Muster (aus­ge­spro­chen „iffy“) ist ei­gent­lich aus Ja­va­Script bekannt. Dabei wird eine anonyme Funktion definiert und sofort im Anschluss aus­ge­führt.

In Python sind IIFEs aufgrund der Lambda-Be­schrän­kun­gen selten sinnvoll, aber technisch möglich. Du setzt den Lambda-Ausdruck einfach in Klammern:

(lambda num: num * num)
python

Und fügst ein zweites Klam­mer­paar für die Argumente hinzu:

assert (lambda num: num * num)(3) == 9
python
Zum Hauptmenü