Python typing module - Use type checkers effectively
A practical guide to python type hints: how to use the python typing module, write python type annotations for functions and variables, work with type aliases and NewType, use Any, and run the mypy type checker.
Drake Nguyen
Founder · System Architect
Introduction to python type hints
Since Python 3.5 the python typing module has offered a standard way to add type information to code. These python type hints (also called python type annotations) are cues for static tools and developers — they make intent explicit, improve readability, and enable static analyzers to find potential problems before runtime.
Type hints Netalith not change Python’s runtime behavior. To catch mismatches you should use a static type checker such as mypy type checker or an IDE with python type checking support.
Recommended prerequisites
To follow examples and check types locally, install mypy and a modern Python (3.8+ recommended). A typical installation command is:
pip install mypy
Run a static check with:
mypy program.py
After fixing type issues reported by the mypy type checker you can run the script normally:
python program.py
Type hints and python type annotations for functions and variables
Annotating functions
You can annotate parameters and return values to document behavior and enable static checking. For example:
from typing import List
def print_list(a: List[int]) -> None:
print(a)
print_list([1, 2, 3])
print_list(1) # mypy will flag this as an error
Using these python type hints helps tools like mypy detect incorrect calls at analysis time (static type checking), improving reliability.
Annotating variables
PEP 526 introduced variable annotations. They let you declare the expected type for a variable without changing runtime semantics:
radius: float = 1.5
sample: int # annotated but not initialized
def area(r: float) -> float:
return 3.1415 * r * r
print(area(radius))
print(area.__annotations__)
Inspecting the __annotations__ dictionary can be useful for tooling and documentation generation.
Type aliases and python typing module examples: List, Dict
Type aliases simplify repeated complex types. Use them to make function signatures clearer:
from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
print(scale(2.0, [1.0, 2.0, 3.0]))
For dictionaries, aliases help enforce key/value types during static analysis:
from typing import Dict
ContactDict = Dict[str, str]
def check_if_valid(contacts: ContactDict) -> bool:
import re
for name, email in contacts.items():
if not isinstance(name, str) or not isinstance(email, str):
return False
if not re.match(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+$", email):
return False
return True
print(check_if_valid({'alice': '[email protected]'}))
print(check_if_valid({'alice': '[email protected]', 123: '[email protected]'})) # mypy flags this
Create user-defined datatypes using typing.NewType
NewType lets you create distinct semantic types that the static checker treats separately from their base type. This is useful to avoid mixing logically different integers, strings, etc.
from typing import NewType
StudentID = NewType('StudentID', int)
def get_student_name(stud_id: StudentID) -> str:
return input(f'Enter username for ID #{stud_id}:\n')
stud = get_student_name(StudentID(100))
# get_student_name(100) -> mypy will complain: expected StudentID
The Any type and mixing dynamic code
typing.Any tells static checkers that any type is permitted. It is useful when interacting with dynamically typed APIs or when gradually adding annotations.
from typing import Any
def echo(x: Any) -> Any:
return x
print(echo([1, 2, 3]))
print(echo(1))
Note: functions or variables without annotations are implicitly treated as Any by most static checkers.
Best practices for python type hints
- Prefer concise, clear annotations — use type aliases for repeated complex types.
- Run a static type checker (mypy) regularly during development to catch type errors early.
- Use typing.NewType for distinct semantic types to avoid accidental mixing.
- Reserve Any for boundaries where you cannot or will not add full annotations.
- Keep annotations up to date with code; stale hints can mislead linters and readers.
Conclusion
python type hints from the python typing module provide a practical way to introduce static type checking into Python projects. When combined with tools like the mypy type checker, annotations improve maintainability, documentation, and the ability to catch errors before runtime.
References
- Python documentation: typing module, PEP 484 and PEP 526 (official specs for type hints and variable annotations)
- mypy — a widely used mypy type checker for static analysis of python type hints