runtime
139 / 250
lesson 139 Data Models & Typing · advanced

Type hints: documenting types

Type hints say what a function takes and returns: line_total(quantity: int, unit_price: float) -> float. Python stores them but doesn't check them; tools such as mypy read them to catch mistakes before the program runs.

You'll be able to
  • Annotate parameters and return values, including list[str], dict[str, float] and X | None
  • Show that hints are stored (get_type_hints) but not enforced when the code runs
  • Use hints at run time on purpose, to check a record's field types
The idea

A function's name says what it does; its type hints say what goes in and out. quantity: int annotates a parameter, -> float the return value. Collections say what they hold: list[str], dict[str, float], tuple[str, int]. str | None means "a text, or None", which is how a lookup that can fail is written.

Hints are documentation that tools can read. Python itself stores them and otherwise ignores them: nothing checks them when the function is called. A static type checker such as mypy, which you run on your computer (mypy shop.py), reads the hints and reports calls that don't match before the program ever runs. Editors use them for completion and warnings. In this course's browser there is no type checker; what you can see here is what Python itself does.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Hints on two shop functions
from typing import get_type_hints

def line_total(quantity: int, unit_price: float, discount: float = 0.0) -> float:
    return round(quantity * unit_price * (1 - discount), 2)

def find_customer(customers: dict[str, str], customer_id: str) -> str | None:
    return customers.get(customer_id)

print(line_total(2, 17.92), line_total(3, 10, 0.1))
print(find_customer({"C00077": "Jamal Walker"}, "C99999"))
print(get_type_hints(line_total))
example-2.py · Hints don't stop a wrong call
def order_total(prices: list[float]) -> float:
    return sum(prices)

print(order_total([4.75, 12.5]))
print(order_total(["4.75", "12.50"]))

Because hints are ordinary values you can read, a program can use them on purpose at run time. Data-validation libraries (pydantic, for example) are built on exactly that. Here is the core of the idea, for a dataclass: compare each field's value with its annotated type.

example-3.py · Checking a record against its hints
from dataclasses import dataclass, fields
from typing import get_type_hints

@dataclass
class Payment:
    payment_id: str
    order_id: str
    amount: float
    instalments: int = 1

def type_problems(record) -> list[str]:
    hints = get_type_hints(type(record))
    problems = []
    for f in fields(record):
        value = getattr(record, f.name)
        expected = hints[f.name]
        if not isinstance(value, expected):
            problems.append(f"{f.name}: expected {expected.__name__}, got {type(value).__name__}")
    return problems

good = Payment("PAY10231", "O100282", 35.84)
bad = Payment("PAY10232", 100918, "55.72", 3)
print(type_problems(good))
print(type_problems(bad))

When to use it: on functions other people (or you, later) call, and on every dataclass field. Hints pay off most in larger programs, together with a type checker in your editor or CI.

Mistakes to avoid: believing hints validate input (they don't; validate real input yourself); a return hint that lies (-> float on a function that can return None should be -> float | None); and list without the item type when the item type matters.

Review
  • param: type and -> type document a function; list[str], dict[str, float] and X | None describe collections and optional values.
  • Python stores hints (get_type_hints) but doesn't check them; a static checker such as mypy does, before the program runs.
  • Hints are values, so code can read them on purpose, for example to validate a record.
  • Next: describing dictionary shapes and interfaces with TypedDict and Protocol.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Type hints: documenting types — Data Models & Typing · Runtime