20% Rabatt mit Code ERSTIS26
4 min Lesezeit 02. Sept. 2026

Python Typannotationen und Generics einfach erklärt

Typannotationen und Generics in Python erklärt: So nutzt du Type Hints für lesbaren, wartbaren Code – mit Beispielen für Einsteiger.

Marcel Schmidtpeter Von Marcel Schmidtpeter 02. Sept. 2026
Python Typannotationen und Generics einfach erklärt

Du öffnest ein Python-Projekt von einem Kollegen und findest diese Funktion:

python
def verarbeite_daten(daten):
    return daten[0]

Was kommt hier rein? Eine Liste? Ein Dictionary? Und was kommt raus? Niemand verrät es dir - du musst den kompletten Code drumherum lesen. Genau für dieses Problem gibt es Typannotationen (englisch: Type Hints). Und wenn du sie richtig nutzt, kommst du automatisch bei Generics raus. Beide Konzepte erklären wir dir hier Schritt für Schritt.

Was sind Typannotationen in Python?

Typannotationen sind Hinweise im Code, die beschreiben, welchen Datentyp eine Variable, ein Funktionsparameter oder ein Rückgabewert haben soll. Typannotationen gibt es offiziell seit Python 3.5 - definiert in PEP 484.

So sieht der Unterschied aus:

python
# Ohne Typannotationen
def addiere(a, b):
    return a + b


# Mit Typannotationen
def addiere(a: int, b: int) -> int:
    return a + b

Die Syntax ist einfach: Nach dem Parameternamen kommt ein Doppelpunkt, dann der Typ. Der Rückgabetyp steht nach dem Pfeil `->` am Ende der Funktionsdefinition.

Merke: Typannotationen sind nur Hinweise. Python prüft sie zur Laufzeit nicht. Du kannst trotzdem `addiere("a", "b")` aufrufen, ohne dass ein Fehler passiert.

Warum dann überhaupt annotieren? Weil drei Gruppen davon profitieren:

  1. Du selbst, weil der Code selbstdokumentierend wird

  2. Deine IDE (z. B. PyCharm oder VS Code), die dir Autovervollständigung und Warnungen liefert

  3. Typprüfer wie mypy, die deinen Code statisch analysieren - also vor dem Ausführen

Gerade in der Ausbildung, im Studium oder im ersten Job bekommst du dafür Pluspunkte: Teams erwarten Type Hints in größeren Projekten meist als Standard.

Welche Typen kannst du annotieren?

Für einfache Datentypen wie `int` oder `str` schreibst du den Typ direkt hin. Für komplexe Datentypen nutzt du eckige Klammern, um den Inhaltstyp anzugeben. Wenn du die Grundlagen zu Listen und Dictionaries auffrischen willst, wirf einen Blick in unseren Überblick zu Python Collections.

Annotation

Bedeutung

Beispiel-Wert

`int`

Ganzzahl

`42`

`str`

Zeichenkette

`"Hallo"`

`float`

Kommazahl

`3.14`

`bool`

Wahrheitswert

`True`

`list[int]`

Liste von Ganzzahlen

`[1, 2, 3]`

`dict[str, int]`

Dictionary: Text-Schlüssel, Zahl-Werte

`{"alter": 25}`

`tuple[int, str]`

Tupel mit fester Struktur

`(1, "a")`

`int \

None`

Zahl oder `None`

Der Typ `int | None` (gesprochen: "int oder None") brauchte früher das `Optional[int]` aus dem `typing`-Modul. Seit Python 3.10 reicht das Pipe-Zeichen - deutlich lesbarer.

Ein komplettes Beispiel:

python
def zaehle_woerter(text: str) -> int:
    return len(text.split())


def finde_nutzer(namen: list[str], index: int) -> str | None:
    if index < len(namen):
        return namen[index]
    return None

Beachte: `finde_nutzer` kann auch `None` zurückgeben, weil der Index außerhalb der Liste liegen kann. Genau solche Fälle macht `str | None` explizit sichtbar - für dich und für deine IDE.

Was sind Generics in Python?

Generics sind Typen mit Platzhaltern, die erst bei der Verwendung durch einen konkreten Typ ersetzt werden. Stell dir ein Formular vor, in dem "Name: ____" steht - der Platzhalter wird später ausgefüllt. Bei Generics füllt der Typ `T` diese Lücke aus.

Das Problem: Du willst eine Funktion schreiben, die das erste Element einer Liste zurückgibt. Egal ob Zahlen, Namen oder Bestellungen. Mit `list[str]` wärst du auf Zeichenketten festgelegt. Die Lösung ist ein TypeVar - die Variable für einen Typ:

python
from typing import TypeVar

T = TypeVar("T")


def erstes_element(liste: list[T]) -> T:
    return liste[0]


zahl = erstes_element([10, 20, 30])  # T ist jetzt int
name = erstes_element(["Anna", "Ben"])  # T ist jetzt str

Das Geniale: Beim Aufruf mit `list[int]` "weiß" der Typprüfer, dass `zahl` ein `int` ist - und beim Aufruf mit `list[str]`, dass `name` ein `str` ist. Ein Code, typsicher für alle Datentypen.

Seit Python 3.12 geht das dank PEP 695 sogar ohne den Import:

python
def erstes_element[T](liste: list[T]) -> T:
    return liste[0]

Merke: `T` ist kein "irgendein Typ, alles darf gemischt werden". Innerhalb eines Aufrufs muss `T` überall derselbe Typ sein. Wer eine `list[int]` übergibt, bekommt ein `int` zurück - nicht plötzlich ein `str`.

Praxisbeispiel: Eine generische Stack-Klasse

Klassiker aus Ausbildung und Studium: ein Stack (Stapel-Datenstruktur, LIFO-Prinzip - Last In, First Out). Mit Generics baust du ihn einmal - für alle Typen.

python
from typing import TypeVar, Generic

T = TypeVar("T")


class Stack(Generic[T]):
    def __init__(self):
        self._elemente: list[T] = []

    def push(self, element: T) -> None:
        self._elemente.append(element)

    def pop(self) -> T:
        if self.ist_leer():
            raise IndexError("Stack ist leer")
        return self._elemente.pop()

    def ist_leer(self) -> bool:
        return len(self._elemente) == 0

Die Klasse erbt von `Generic[T]` und deklariert damit: "Ich arbeite mit einem Typ, den der Nutzer beim Erzeugen festlegt." So nutzt du sie:

python
zahlen: Stack[int] = Stack[int]()
zahlen.push(1)
zahlen.push(2)
print(zahlen.pop())  # 2

namen: Stack[str] = Stack[str]()
namen.push("Anna")
print(namen.pop())  # Anna

Deine IDE erkennt: `zahlen.pop()` liefert ein `int`, `namen.pop()` ein `str`. Wenn du danach versuchst, `zahlen.pop() + "x"` zu schreiben, warnt dich der Typprüfer sofort. Die offizielle Dokumentation dazu findest du im `typing`-Modul der Python-Docs.

Welche 3 Anfängerfehler solltest du vermeiden?

Fehler 1: Glauben, dass Python die Typen durchsetzt. Type Hints sind reine Deklarationen. `addiere("a", "b")` läuft ohne Fehlermeldung durch - obwohl laut Annotation nur `int` erlaubt ist. Wer Typen wirklich prüfen will, braucht ein Tool wie mypy:

bash
pip install mypy
mypy mein_skript.py

Fehler 2: `None` als Standardwert ohne Typ-Anpassung. Häufiger Stolperstein:

python
# Falsch: None passt nicht zu str
def begruessung(name: str = None) -> str:
    return "Hallo " + name


# Richtig
def begruessung(name: str | None = None) -> str:
    if name is None:
        return "Hallo Gast"
    return "Hallo " + name

Fehler 3: `list[int]` in alten Python-Versionen nutzen. Die eingebaute Schreibweise mit eckigen Klammern gibt es erst seit Python 3.9. Davor musste man `List[int]` aus dem `typing`-Modul importieren. Wenn du in einer Firma noch auf Python 3.8 arbeitest, knallt `list[int]` mit einem `TypeError`. Die neue `def f[T]()`-Syntax wiederum braucht Python 3.12. Immer kurz checken, welche Version im Projekt läuft.

Dein Übungstipp für heute

Nimm ein eigenes Skript - oder eines aus deinen Lernunterlagen - und annotiere jede Funktion: Parameter und Rückgabewert. Danach führe `mypy` aus und schau, welche Fehler er findet. Du wirst überrascht sein, wie viele versteckte `None`-Fälle und Typ-Mixe in deinem eigenen Code schlummern. Das ist übrigens auch eine beliebte Frage in Prüfungen und Vorstellungsgesprächen.

FAQ: Häufige Fragen zu Typannotationen und Generics

Werden Typannotationen in Python zur Laufzeit geprüft?

Nein. Python bleibt dynamisch typiert - Type Hints sind nur Hinweise für Menschen, IDEs und statische Analysetools wie mypy oder Pyright.

Seit wann gibt es `list[int]` statt `List[int]`?

Seit Python 3.9. Davor musste `List` aus dem `typing`-Modul importiert werden. Seit Python 3.10 gibt es zusätzlich `int | None` statt `Optional[int]`.

Was bedeutet `T` bei Generics?

`T` ist eine Typvariable (TypeVar) - ein Platzhalter, der beim Aufruf durch einen konkreten Typ ersetzt wird. Innerhalb eines Aufrufs bleibt er konsistent.

Brauche ich Typannotationen in jedem Projekt?

Nein, sie sind optional. In kleinen Skripten verzichtet man oft darauf. In größeren Projekten und Teams sind sie aber Quasi-Standard, weil sie Fehler früh sichtbar machen.

Was ist der Unterschied zwischen `Optional[int]` und `int | None`?

Kein inhaltlicher - beide bedeuten "int oder None". Die Pipe-Schreibweise ist seit Python 3.10 die moderne, lesbare Variante.

Fazit

Typannotationen machen deinen Python-Code lesbar und werkzeugfreundlich, ohne die dynamische Natur von Python aufzugeben. Generics gehen einen Schritt weiter: eine Funktion oder Klasse schreiben, typsicher für alle Datentypen nutzen. Starte mit einfachen Annotationen wie `str` und `int`, arbeite dich zu `list[T]` und generischen Klassen vor - und lass mypy regelmäßig drüberschauen.

Wenn du dich gezielt auf Prüfungen, Abschlussarbeiten oder dein erstes Job-Interview vorbereiten willst: Bei study-it.education bekommst du individuelle Nachhilfe für Python, Java, C# und alle Themen rund um deine IT-Ausbildung oder dein Studium. Schau vorbei und lerne mit Leuten, die sich auch mit `__str__` und `__eq__` auskennen - mehr dazu in unserem Artikel zu Python Dunder-Methoden.


Erstgespräch · 0 € · 30 min

Brauchst du jemand, der das mit dir durchgeht?

Statt nochmal lesen: 30 min mit einem Senior-Dev.

Kostenloses Erstgespräch buchen →
Über den Autor
Marcel Schmidtpeter
Marcel Schmidtpeter

Typannotationen und Generics in Python erklärt: So nutzt du Type Hints für lesbaren, wartbaren Code – mit Beispielen für Einsteiger.

marcel.schmidtpeter@study-it.education →
Weiterlesen

Mehr Lesestoff