Chapter 17: Type Hints & Static Typing

Add type annotations to functions, variables and classes, and leverage the typing module for safer, self-documenting code.

Download chapter17.py

Objectives

1. Function Annotations

def greet(name: str) -> str:
    return f"Hello, {name}"

def add(a: int, b: int) -> int:
    return a + b

print(greet.__annotations__)
# {'name': , 'return': }

2. Variable Annotations

from typing import List

ages: List[int] = [25, 30, 35]
threshold: float = 4.5

print(globals().get('__annotations__'))
# {'ages': list[int], 'threshold': float}

3. Common Types from typing

from typing import Optional, Union, Any, Dict

def find_user(user_id: int) -> Optional[Dict[str, Any]]:
    users = {1: {"name": "Alice"}}
    return users.get(user_id)

def process(data: Union[str, bytes]) -> None:
    print(data)

user = find_user(2)
if user is None:
    print("Not found")

4. Generics & TypeVar

from typing import TypeVar, Generic, List

T = TypeVar('T')

class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: List[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

int_stack = Stack[int]()
int_stack.push(1)
str_stack = Stack[str]()
str_stack.push("hello")

5. Static Type Checking with mypy

pip install mypy
mypy src/chapter17.py --strict

Fix reported mismatches to ensure annotations align with usage.

Exercises

  1. Add type hints to a small calculator module (add, sub, mul, div).
  2. Annotate a data-loading function returning List[Dict[str, Any]].
  3. Create a generic Queue[T] class with enqueue() and dequeue().
  4. Run mypy on your code and resolve all type errors.