Python ist dynamisch typisiert: Eine Variable kann nacheinander Zahl, Text und Liste enthalten. Mit Typ-Hints (Typannotationen) schreibst du dazu, welche Typen du erwartest. Python führt sie nicht aus, aber Editoren und Prüfwerkzeuge wie mypy oder pyright finden damit Fehler, bevor das Programm läuft, und der Code ist besser lesbar.
Grundlagen
name: str = "Mia"
alter: int = 17
preis: float = 9.99
aktiv: bool = True
def begruessen(name: str, laut: bool = False) -> str:
text = f"Hallo {name}"
return text.upper() if laut else text
print(begruessen("Tom"))
print(begruessen("Tom", laut=True))
print(begruessen.__annotations__)Hallo Tom
HALLO TOM
{'name': <class 'str'>, 'laut': <class 'bool'>, 'return': <class 'str'>}Nach dem Doppelpunkt steht der Typ eines Parameters, nach dem Pfeil -> der Typ des Rückgabewerts. None als Rückgabetyp bedeutet "gibt nichts zurück".
Sammlungen
Seit Python 3.9 schreibst du die eingebauten Typen direkt mit eckigen Klammern:
def mittelwert(zahlen: list[float]) -> float:
return sum(zahlen) / len(zahlen)
def zaehle(woerter: list[str]) -> dict[str, int]:
ergebnis: dict[str, int] = {}
for w in woerter:
ergebnis[w] = ergebnis.get(w, 0) + 1
return ergebnis
punkt: tuple[int, int] = (3, 4)
ids: set[int] = {1, 2, 3}
print(mittelwert([1, 2, 3, 4]))
print(zaehle(["a", "b", "a"]))2.5
{'a': 2, 'b': 1}| Hint | Bedeutung |
|---|---|
list[int] | Liste von ganzen Zahlen |
dict[str, float] | Dictionary von Text auf Kommazahl |
tuple[int, str] | Tupel aus genau zwei Elementen |
tuple[int, ...] | Tupel beliebiger Länge aus ints |
set[str] | Menge von Texten |
Optional und Vereinigungen
Kann ein Wert auch None sein oder zwei Typen haben, schreibst du | (ab Python 3.10):
def finde(liste: list[str], gesucht: str) -> int | None:
for i, eintrag in enumerate(liste):
if eintrag == gesucht:
return i
return None
def verdopple(x: int | float) -> int | float:
return x * 2
print(finde(["a", "b"], "b"), finde(["a", "b"], "z"))
print(verdopple(2), verdopple(2.5))1 None 4 5.0
Weitere nützliche Typen
from typing import Any, Callable, Literal, TypedDict
def anwenden(f: Callable[[int], int], wert: int) -> int:
return f(wert)
def richtung(r: Literal["links", "rechts"]) -> str:
return f"geh nach {r}"
class Nutzer(TypedDict):
name: str
alter: int
n: Nutzer = {"name": "Mia", "alter": 17}
print(anwenden(lambda x: x + 1, 4))
print(richtung("links"))
print(n["name"])5 geh nach links Mia
| Typ | Bedeutung |
|---|---|
Any | beliebig (schaltet die Prüfung ab) |
Callable[[A, B], R] | Funktion mit Parametern A, B und Rückgabe R |
Literal["a", "b"] | nur diese festen Werte |
TypedDict | Dictionary mit festen Schlüsseln |
Iterable[T], Sequence[T] | allgemeine Sammlungen (aus collections.abc) |
Eigene Klassen und Generics
from dataclasses import dataclass
from typing import TypeVar
T = TypeVar("T")
@dataclass
class Punkt:
x: int
y: int
def abstand(a: Punkt, b: Punkt) -> float:
return ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5
def erstes(liste: list[T]) -> T: # T steht für "irgendein Typ"
return liste[0]
print(abstand(Punkt(0, 0), Punkt(3, 4)))
print(erstes([10, 20]), erstes(["x", "y"]))5.0 10 x
Ab Python 3.12 geht es kürzer: def erstes[T](liste: list[T]) -> T: braucht keine TypeVar-Zeile mehr.
Prüfen mit mypy
Typ-Hints ändern das Laufzeitverhalten nicht. Fehler findest du mit einem Prüfprogramm:
pip install mypy
mypy meine_datei.py# mypy würde hier melden: Argument 1 has incompatible type "str"; expected "int"
def doppelt(x: int) -> int:
return x * 2
print(doppelt("ab"))abab
Das Programm läuft trotzdem, weil Python die Hints nicht erzwingt. Erst mypy schlägt Alarm.
Merke
x: intannotiert Variablen,-> strden Rückgabewertlist[int],dict[str, int],tuple[int, int]für Sammlungenint | Nonefür optionale Werte- Hints werden nicht erzwungen; mypy oder pyright prüfen sie
Callable,Literal,TypedDict,Anyfür Sonderfälle
Aufgabe
Annotiere eine Funktion teile(text: ..., trenner: ...), die einen Text an einem Trenner teilt und die Teile als Liste zurückgibt, und eine Funktion, die den längsten Text aus einer Liste oder None liefert.