Tutorial

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

3 min read
Python typing module - Use type checkers effectively
Python typing module - Use type checkers effectively

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

Stay updated with Netalith

Get coding resources, product updates, and special offers directly in your inbox.