Background
Function annotations were introduced in Python 3.0, and the type hints mechanism is described in PEP 484, added in 3.5. This tool is designed for static code analysis, autocompletion, and improving readability — the standard library typing allows explicitly specifying expected types of variables, arguments, and return values of functions.
Problem
Python is a dynamic language where variable types can change at runtime, which can lead to errors only at the execution stage of the program. Annotations do not affect code execution, but when misused, developers have a false sense of "strict typing."
Solution
Type annotations are used for documentation, automatic checking with tools like mypy, pylance, pyright, and similar, as well as integration with IDEs. They are implemented with a colon after the argument name and an arrow after the parameter list:**
def greet(name: str, times: int = 1) -> None: for _ in range(times): print(f"Hello, {name}!") # Correct annotation for a function processing a dictionary from typing import Dict, List def transform(data: Dict[str, List[int]]) -> float: return sum(sum(lst) for lst in data.values()) / 10
Key features:
typing.List, typing.Dict, typing.Optional, typing.Union, etc., are needed.Can Python "automatically" check type conformity declared in annotations?
No! Type checking occurs only through external static analysis tools, such as mypy. At runtime, Python completely ignores the contents of annotations.
def f(x: int): return x * 2 print(f('oops')) # Type str, there will be no error!
Where are annotations stored and how can they be accessed at runtime, and why might this be needed?
They are stored in a special attribute __annotations__:
def add(x: int, y: int) -> int: return x + y print(add.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
This is used by third-party libraries for data validation, autogeneration of documentation, serialization, etc.
Can any variable be annotated, just functions, and what happens in the global scope?
Both local and global variables can be annotated with a colon; this also does not affect execution:
index: int = 0 def func(x: 'User') -> None: ...
typing (e.g., List<int> instead of List[int])In a corporate project, all developers began actively implementing annotations, yet the actual types of function arguments often did not match those specified. Python allowed these errors, and unexpected bugs only appeared deep within the business logic. There was no mypy configuration set up.
Pros:
Cons:
Using type hints and mandatory running of mypy in CI, as well as autogeneration of documentation from __annotations__:
Pros:
Cons: