New staff read the order dict and guess what 'qty' means. A type hint says it is an int before anyone runs the code. What does Python actually enforce at runtime?
Type hints are optional annotations that describe the values a function expects and returns. Python does not enforce them at runtime, but editors, linters, and teammates can use them to catch mistakes before the program runs. You will also describe callbacks, JSON-like records, and relationships between input and output types.
Annotate a function
The colon after a parameter names its expected type, and the arrow names the return type. Hints are stored in __annotations__, but they do not convert values. Passing a non-string still runs until the code itself fails.
def greet(name: str) -> str:
return f"Hello, {name}"
print(greet("Ada"))Parameters and return type
Describe collections
list[int] says every element is an int. Built-in generics work in modern Python and read clearly. Hints describe the interface; they do not check each item when the function is called.
def total(values: list[int]) -> int:
return sum(values)
print(total([1, 2, 3]))A typed list
Show that a value may be missing
dict.get returns None when a key is absent, so the return type should include None. The union syntax float | None states that possibility directly. Callers can then handle the missing case before doing arithmetic.
def find_price(prices: dict[str, float], item: str) -> float | None:
return prices.get(item)
print(find_price({"tea": 3.5}, "tea"))
print(find_price({"tea": 3.5}, "coffee"))Maybe a value, maybe None
Callable and Iterable describe behavior
A hint can describe what a function accepts, not just a built-in type. Callable[[int], int] says the argument is a function from int to int; Iterable[int] accepts lists, generators, and other streams. The hint helps editors without changing runtime behavior.
from collections.abc import Callable, Iterable
def apply_all(values: Iterable[int], operation: Callable[[int], int]) -> list[int]:
return [operation(value) for value in values]
print(apply_all([1, 2, 3], lambda n: n * 2))Annotate the callback, not just the list
TypedDict describes a record shape
A TypedDict names the keys and value types of a dictionary, which is useful at JSON boundaries. It is still a plain dict at runtime; no key or type check happens automatically. Validate the decoded data separately before trusting it.
from typing import TypedDict
class Order(TypedDict):
drink: str
price: float
quantity: int
order: Order = {"drink": "latte", "price": 4.5, "quantity": 2}
print(order["drink"], order["price"] * order["quantity"])Name the keys without changing the runtime
TypeVar keeps input and output related
A TypeVar says the same type flows through a function. first(list[int]) returns int | None, while first(list[str]) returns str | None. Without the variable, the best you could say is object, which loses useful information for callers.
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T | None:
return items[0] if items else None
print(first([1, 2, 3]))
print(first(["latte"]))
print(first([]))Preserve the element type through the call
Key points
- Parameter hints follow a colon; return hints follow ->.
- list[int] and dict[str, float] describe collection contents.
- float | None means the value may be missing.
- Hints are documentation and tooling input, not runtime enforcement.
- Hints describe interfaces; TypedDict and TypeVar add shape and relationships, not runtime checks.
Common mistakes
- Assuming Python raises TypeError just because a hint is violated.
- Putting a list[int] hint in a comment instead of the function signature.
- Forgetting None in a return type when a lookup can fail.
- Believing a violated annotation raises TypeError by itself.
Annotate double(n: int) -> int, print double(4), and annotate a function that returns str | None.
Try it yourself
Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.
Practice this lesson
12 questions with immediate explanations.