Python Annotations
By Flavio Copes
Python is dynamically typed, but annotations let you optionally add type hints to variables and functions, which tools like mypy can check for type errors.
Annotations let you attach type hints to function parameters, return values and variables. Python is dynamically typed, so it never asks for them, but they document what your code expects and let external tools catch type errors before you run the program.
This is a function without annotations:
def increment(n):
return n + 1
This is the same function with annotations:
def increment(n: int) -> int:
return n + 1
The n: int part says the parameter should be an integer. The -> int part says the function returns an integer.
You can also annotate variables:
count: int = 0
Annotations work together with default values, too:
def greet(name: str = 'Flavio') -> str:
return 'Hello ' + name
Python ignores annotations at runtime
This is the part that surprises people coming from statically typed languages. Annotations are metadata. Python does not check them when the program runs:
def double(n: int) -> int:
return n * 2
print(double('ab'))
# abab
We said n should be an int, then passed a string. Python happily repeated the string instead of complaining.
The annotations are stored in a dictionary attached to the function, and you can look at it:
print(double.__annotations__)
# {'n': <class 'int'>, 'return': <class 'int'>}
So who checks the types?
A separate tool called mypy can be run standalone, or integrated by IDEs like VS Code or PyCharm to automatically check for type errors statically, while you are coding, and it will help you catch type mismatch bugs before even running the code.
Run it against a file:
mypy program.py
It points at every line where the types don’t match, like the double('ab') call above.
A great help especially when your software becomes large and you need to refactor your code.
One thing to be careful with: don’t treat annotations as validation. If a function receives data from user input or an API, the annotation won’t stop a wrong type from getting in. Check the value yourself, or run a type checker as part of your workflow so the mismatch never ships.
Related posts about python: