In Python können ab Version 3.6 Typen im Quelltext annotiert werden. Mit mypy
können diese Typen geprüft werden. Es kann einfach mit pip installiert werden.
$ pip install mypy
Einfache Type können für Zahlen angegeben werden.
a:int = 1
Mit mypy kann die Datei getestet werden.
mypy typentest.py
Wir bauen nun einen Fehler ein.
a:int = 1
a = "eins"
mypy zeigt nun den Fehler an.
mypy typentest.py
typentest.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int")
Funktionen können auch mit Typinformationen ausgestattet werden. Zu Erinnerung: so sehen für gewöhnlich Funktionen aus, wenn sie keine Typinformationen enthalten.
def greet(name):
return "Hallo" + name
Die Funktion kann um Typen ergänzt werden. Es kann sowohl der Parameter als auch der Rückgabewert typisiert werden.
def greeting(name:str) -> str:
return "Hallo" + name
greeting("Otto") # OK
greeting("Du " + "Otto") # OK
greeting(23) # not OK
greeting(False) # not OK
Durch eine Überprüfung können so Fehler im Quelltext entdeckt werden.
mypy typentest.py
typentest.py:8: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"
typentest.py:9: error: Argument 1 to "greeting" has incompatible type "bool"; expected "str"
Nun eine Funktion, die keinen Rückgabewert besitzt.
def func_without_retval() -> None:
print("In p()")
func_without_retval() # OK
result = func_without_retval() # not OK
mypy typentest.py
typentest.py:6: error: "func_without_retval" does not return a value
Es sind auch komplexe Typen wie Listen, Mengen oder Dictionaries erlaubt.
from typing import List, Set
x1:List[int] = [1, 2, 3] # OK
x2:List[int] = [1, 2, 3.3] # not OK
y1:Set[float] = {1.1, 2.2} # OK
y2:Set[float] = {1, "2"} # not OK
mypy typentest.py
typentest.py:5: error: List item 2 has incompatible type "float"; expected "int"
typentest.py:7: error: Argument 2 to <set> has incompatible type "str"; expected "float"
Bei Dictionaries müssen der Typ für den Key und den Value angegeben werden.
from typing import Dict
x:Dict[int, str] = {1: "eins", 2: "zwei"} # OK
y:Dict[int, str] = {"1": "eins", 2: "zwei"} # not OK
mypy typentest.py
typentest.py:5: error: Dict entry 0 has incompatible type "str": "str"; expected "int": "str"
Auch eigene Klassen können als Typen verwendet werden.
class MeineKlasse:
def __init__(self, x:int) -> None:
self.x:int = x
mk1:MeineKlasse = MeineKlasse(23) # OK
mk2:MeineKlasse = MeineKlasse(23.42) # not OK
mypy typentest.py
typentest.py:8: error: Argument 1 to "MeineKlasse" has incompatible type "float"; expected "int"
Die Klasse kann auch in anderen Klassen verwendet werden.
class MeineKlasse:
def __init__(self) -> None:
self.x:int = 23
class AndereKlasse:
def __init__(self, mk: MeineKlasse) -> None:
self.attr: MeineKlasse = mk
mk:MeineKlasse = MeineKlasse()
ak1:AndereKlasse = AndereKlasse(mk) # OK
ak2:AndereKlasse = AndereKlasse(23) # not OK
mypy typentest.py
typentest.py:13: error: Argument 1 to "AndereKlasse" has incompatible type "int"; expected "MeineKlasse"
Weitere Annotationen sind im Cheat Sheet von mypy gelistet.