# Funktionen in Python: def, return, Argumente, *args und **kwargs, lambda und Typannotationen

URL: https://skillaria.top/de/guides/python/funkcii-python

Eine Funktion in Python ist ein benannter Codeblock, den Sie mit def definieren, mit Klammern aufrufen und der über return ein Ergebnis zurückgibt; ohne return liefert sie None. Argumente übergeben Sie der Reihe nach oder mit Namen, *args sammelt überzählige Werte in einem Tupel, **kwargs benannte Werte in einem Dictionary, und lambda erzeugt eine kurze anonyme Funktion aus einem einzigen Ausdruck.

Eine Funktion in Python ist ein benannter Codeblock, den Sie beliebig oft mit verschiedenen Eingabewerten aufrufen können. Sie wird mit `def` definiert, nimmt Werte über Parameter entgegen und liefert das Ergebnis über `return` zurück. Funktionen sind das wichtigste Mittel, um ein langes Skript in verständliche, überprüfbare Schritte zu zerlegen.

## Eine Funktion definieren: def in Python

Die Definition beginnt mit `def`, danach folgen der Name, die Parameter in Klammern und ein Doppelpunkt. Der Körper wird mit vier Leerzeichen eingerückt. Die Einrückung ist in Python kein Schmuck, sondern Teil der Syntax.

```
def greet(name):
    """Gibt eine Begrüßung für den Benutzer zurück."""
    return f"Hallo, {name}!"

print(greet("Anna"))   # Hallo, Anna!
```

Ein Text in dreifachen Anführungszeichen direkt nach der Kopfzeile ist ein Docstring, die Dokumentation der Funktion. Ihn zeigt `help(greet)` und die Hinweise des Editors an. Funktionsnamen schreibt man nach der Konvention PEP 8 in snake_case: `add_expense`, `get_rate`.

Die Zeile `def greet(name):` nennt man Signatur der Funktion: Name plus Liste der Parameter (und Annotationen, falls vorhanden). Anhand der Signatur erkennt der Leser, wie die Funktion aufzurufen ist, ohne den Körper zu lesen.

## Was return in Python macht

`return` beendet die Funktion und gibt einen Wert an den Aufrufer zurück. Code nach einem ausgeführten `return` läuft nicht mehr. Fehlt `return` oder steht es ohne Wert da, liefert die Funktion `None`.

```
def area(w, h):
    w * h          # Ergebnis wird berechnet und verworfen

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12
```

Ein vergessenes `return` ist einer der häufigsten Fehler von Einsteigern: Die Funktion „läuft“, liefert aber `None`, und der Fehler zeigt sich erst in der nächsten Zeile. Man kann auch mehrere Werte zurückgeben. Tatsächlich ist das ein Tupel, das sich bequem entpacken lässt:

```
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9
```

Ein frühes `return` vermeidet unnötige Verschachtelung: Zuerst behandeln Sie die Sonderfälle, danach folgt die eigentliche Logik.

```
def discount(price, is_member):
    if price  limit    # Lesen der globalen Variable — erlaubt

def raise_limit():
    global limit
    limit = 2000             # ohne global würde eine lokale Variable entstehen
```

In der Praxis sollten Sie `global` meiden: Eine Funktion, die einen äußeren Zustand verändert, lässt sich schlecht testen. Besser ist es, den Wert als Argument zu übergeben und das Ergebnis zurückzugeben.

## Verschachtelte Funktionen und Closures

Eine Funktion kann innerhalb einer anderen definiert werden. Die innere Funktion sieht die Variablen der äußeren auch dann, wenn die äußere bereits beendet ist. Das nennt man Closure. Um eine solche Variable zu verändern, dient `nonlocal`.

```
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c(), c(), c())   # 1 2 3
```

Closures bilden die Grundlage für Dekoratoren und Funktionsfabriken.

## Eine Funktion ist auch ein Objekt

In Python ist eine Funktion ein gewöhnliches Objekt: Sie können sie in einer Variablen speichern, an eine andere Funktion übergeben, aus einer Funktion zurückgeben oder in einem Dictionary ablegen. Sie besitzt Attribute wie `__name__`, `__doc__`, `__defaults__` und `__annotations__`.

```
def double(x):
    return x * 2

f = double
print(f(5), f.__name__)                # 10 double
print(list(map(double, [1, 2, 3])))   # [2, 4, 6]
```

## Lambda in Python: anonyme Funktionen

Eine lambda-Funktion ist eine kurze Funktion ohne Namen, deren Körper aus einem einzigen Ausdruck besteht. Das Ergebnis des Ausdrucks wird automatisch zurückgegeben, ein `return` schreibt man nicht.

```
square = lambda x: x ** 2
print(square(4))   # 16

expenses = [("Kaffee", 250), ("Taxi", 600), ("Mittagessen", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses)  # [('Taxi', 600), ('Mittagessen', 450), ('Kaffee', 250)]

print(list(filter(lambda n: n % 2 == 0, range(10))))  # [0, 2, 4, 6, 8]
```

Lambda-Funktionen in Python eignen sich gut als kurzes Argument für `sorted`, `max`, `map` oder `filter`. Eine Lambda einer Variablen zuzuweisen, wie `square` oben, empfiehlt PEP 8 nicht. Wenn eine Funktion einen Namen braucht, schreiben Sie `def`. Dann steht ein sinnvoller `__name__` im Traceback, und es gibt Platz für einen Docstring.

|  | def | lambda |
| --- | --- | --- |

| Name | vorhanden | keiner (`<lambda>`) |

| Körper | beliebig viele Anweisungen | ein einziger Ausdruck |

| return | ausdrücklich | implizit |

| Docstring, Annotationen | ja | nein |

| Wo sinnvoll | überall | kurzer key oder Callback |

## Typannotationen: Hinweise, keine Prüfungen

Annotationen beschreiben die erwarteten Typen von Parametern und Ergebnis. Python selbst prüft sie zur Laufzeit nicht: Eine Funktion mit `x: int` nimmt problemlos eine Zeichenkette an. Geprüft werden Annotationen von externen Werkzeugen wie mypy, pyright oder ty und vom Editor, der Fehler schon vor dem Start markiert.

```
def add_expense(title: str, amount: float, category: str = "Sonstiges") -> dict[str, object]:
    return {"title": title, "amount": amount, "category": category}

def area(w: float, h: float) -> float:
    w * h   # mypy: Missing return statement
```

Eine Prüfung ohne Installation starten Sie mit `uvx mypy .`. Das Beispiel oben zeigt den Nutzen der Annotationen: Ein vergessenes `return` bei `-> float` findet der Analysator sofort.

Seit Python 3.12 (PEP 695) schreibt man generische Funktionen ohne `TypeVar`: Der Typparameter steht in eckigen Klammern, ein Typalias wird mit dem Wort `type` deklariert.

```
def first[T](xs: list[T]) -> T:
    return xs[0]

type Money = int | float
```

In Python 3.14 (PEP 649) sind Annotationen lazy geworden: Sie werden erst beim ersten Zugriff ausgewertet. Deshalb können Sie auf eine Klasse verweisen, die weiter unten definiert ist, ohne Anführungszeichen, und `from __future__ import annotations` ist nicht mehr nötig.

## „Nicht übergeben“ oder „None übergeben“: Sentinel in 3.15

Der Standardwert `None` erlaubt keine Unterscheidung zwischen „Argument nicht übergeben“ und „bewusst None übergeben“. Jahrelang löste man das mit einem selbst gebauten Platzhalter:

```
_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default
```

In Python 3.15 gibt es die eingebaute Funktion `sentinel` (PEP 661): `MISSING = sentinel("MISSING")` erzeugt einen eindeutigen Marker mit verständlicher Darstellung, der beim Kopieren er selbst bleibt, sich über pickle serialisieren lässt und sich in einer Annotation wie `float | MISSING` verwenden lässt. Auf älteren Versionen funktioniert weiterhin der Trick mit `object()`.

## Typische Fehler mit Funktionen

- **return vergessen** — die Funktion liefert `None`.
- **Klammern vergessen** — `print(greet)` gibt das Funktionsobjekt aus, nicht das Ergebnis des Aufrufs.
- **Veränderlicher Standardwert** — eine gemeinsame Liste für alle Aufrufe.
- **Falsche Anzahl von Argumenten** — `TypeError: greet() missing 1 required positional argument: 'name'`.
- **Der Name entspricht einer eingebauten Funktion** — eine Funktion namens `list` oder `sum` verdeckt die eingebaute.

## Fazit

Funktionen in Python werden mit `def` definiert, liefern ihr Ergebnis über `return` und nehmen Argumente der Reihe nach oder mit Namen entgegen. `*args` und `**kwargs` bringen Flexibilität, `/` und `*` sorgen für strikte Aufrufe, lambda ist kurz und praktisch für einmalige Funktionen, und Typannotationen finden zusammen mit mypy Fehler vor dem Start. Im Kurs wird dieses Thema praktisch behandelt: Der Ausgabentracker wird in Funktionen mit Annotationen zerlegt und mit mypy geprüft.

## FAQ

**Worin unterscheidet sich ein Parameter von einem Argument?**

Ein Parameter ist der Name in der Definition der Funktion, ein Argument ist der konkrete Wert beim Aufruf. In def greet(name) ist name der Parameter, in greet("Anna") ist die Zeichenkette "Anna" das Argument.

**Kann ich eine Funktion vor ihrer Definition aufrufen?**

Auf Modulebene nicht: Die Zeile def muss vor dem Aufruf ausgeführt werden, sonst gibt es einen NameError. Innerhalb einer anderen Funktion können Sie aber eine später definierte Funktion aufrufen, sofern der Aufruf nach ihrer Definition erfolgt.

**Wie viele Werte kann eine Funktion zurückgeben?**

Formal nur einen, aber dieser Wert kann ein Tupel sein. return a, b gibt ein Tupel aus zwei Elementen zurück, das Sie mit x, y = f() entpacken.

**Muss ich Typannotationen schreiben?**

Nein, Python funktioniert auch ohne sie. Im Code, den andere Menschen lesen, erleichtern sie die Wartung erheblich, und mypy oder pyright finden damit Fehler vor dem Start.

**Kann ich in einer lambda ein if verwenden?**

Nur als bedingten Ausdruck: lambda x: "gerade" if x % 2 == 0 else "ungerade". Anweisungen, Schleifen und Zuweisungen sind in einer lambda nicht erlaubt.


---
Source: Skillaria.Top (https://skillaria.top)
