Type Hints
Type Hints for Collections
When you pass a list of user IDs to a function, how does the function know they should be integers? Collection type hints like list[int] and dict[str, User] make data structures self-documenting and catch type mismatches before they cause runtime errors.
Abstract Collection Types
From typing:
Sequence[T]- read-only-ish sequence interface (works forlist,tuple, etc.)Mapping[K, V]- read-only-ish mapping interface (works fordict)Iterable[T]- any iterable input
list.py
# list[T]
# Typed list
names: list[str] =
print("names:", names)
# Append/extend
names.append("Dora")
names.extend(["Eve", "Frank"])
print("after append/extend:", names)
# Indexing and slicing
first: str = names[0]
last_two: list[str] = names[-2:]
print("first:", first)
print("last_two:", last_two)
# List of numbers
scores: list[int] = [10, 20, 15]
print("scores:", scores)
print("sum:", sum(scores))
# list[T]
# Typed list
names: list[str] =
print("names:", names)
# Append/extend
names.append("Dora")
names.extend(["Eve", "Frank"])
print("after append/extend:", names)
# Indexing and slicing
first: str = names[0]
last_two: list[str] = names[-2:]
print("first:", first)
print("last_two:", last_two)
# List of numbers
scores: list[int] = [10, 20, 15]
print("scores:", scores)
print("sum:", sum(scores))
# list[T]
# Typed list
names: list[str] =
print("names:", names)
# Append/extend
names.append("Dora")
names.extend(["Eve", "Frank"])
print("after append/extend:", names)
# Indexing and slicing
first: str = names[0]
last_two: list[str] = names[-2:]
print("first:", first)
print("last_two:", last_two)
# List of numbers
scores: list[int] = [10, 20, 15]
print("scores:", scores)
print("sum:", sum(scores))
dict.py
# dict[K, V]
# Typed dict
ages: dict[str, int] = {"Alice": 30, "Bob": 27}
print("ages:", ages)
# Insert/update
ages["Charlie"] = 40
ages["Alice"] = ages["Alice"] + 1
print("after update:", ages)
# Lookup with get
maybe_age: int | None = ages.get("Dora")
print("ages.get('Dora'):", maybe_age)
# Iteration
for name, age in ages.items():
print(f" {name} -> {age}")
set_tuple.py
# set[T] and tuple[...]
# set[str]
tags: set[str] = {"python", "typing", "python"}
print("tags:", tags)
# set operations
more: set[str] = {"docs", "typing"}
print("union:", tags | more)
print("intersection:", tags & more)
# tuple with fixed length/types
point: tuple[float, float] = (1.5, 2.0)
print("point:", point)
# tuple with variable length
numbers: tuple[int, ...] = (1, 2, 3, 4)
print("numbers:", numbers)
nested.py
# Nested collection types
# list[dict[str, int]]
rows: list[dict[str, int]] = [
{"id": 1, "score": 10},
{"id": 2, "score": 30},
{"id": 3, "score": 20},
]
print("rows:", rows)
# Compute aggregate
scores: list[int] = [r["score"] for r in rows]
print("scores:", scores)
print("avg score:", sum(scores) / len(scores))
# dict[str, list[str]]
groups: dict[str, list[str]] = {
"admins": ["Alice", "Bob"],
"users": ["Charlie"],
}
print("groups:", groups)
# Safe updates
new_user: str = "Dora"
groups.setdefault("users", []).append(new_user)
print("after add:", groups)
abstract_types.py
# Abstract collection types
from typing import Iterable, Mapping, Sequence
# Prefer abstract types in parameters
def total(values: Iterable[int]) -> int:
return sum(values)
def first_item(values: Sequence[str]) -> str:
return values[0]
def describe(mapping: Mapping[str, int]) -> str:
parts = [f"{k}={v}" for k, v in mapping.items()]
return ", ".join(parts)
print("total([1,2,3]) =", total([1, 2, 3]))
print("total((1,2,3)) =", total((1, 2, 3)))
print("first_item(['a','b']) =", first_item(["a", "b"]))
print("first_item(('x','y')) =", first_item(("x", "y")))
print("describe({'a':1,'b':2}) =", describe({"a": 1, "b": 2}))
Prefer abstract types for function parameters when you only need a subset of behavior.
generic type - a parameterized type like `list[T]` where `T` specifies the element type
tuple type - fixed-length `tuple[T1, T2]` for heterogeneous data, or `tuple[T, ...]` for variable-length
abstract types - types like `Sequence[T]` and `Mapping[K, V]` that accept multiple concrete types
Exercise: practical.py
Type a function that processes nested configuration data