As AI codebases grow—RAG pipelines, evaluation harnesses, FastAPI services—clarity of data shapes matters. Type hints annotate variables, parameters, and return values so humans and tools (mypy, Pyright, IDEs) understand expected types before runtime failures occur.
Type hints do not slow Python down by default; they are optional metadata that improve maintainability, especially when collaborating on production ML systems.
Learning Objectives
By the end of this lesson, students should be able to:
- Annotate functions with parameter and return types.
- Use built-in generics:
list[str],dict[str, int],tuple[float, ...]. - Import and use
Optional,Union, andTypedDictfromtyping. - Understand that type hints are not enforced at runtime by default.
- Run static checkers (mypy / Pyright) on AI utility modules.
- Read typed signatures in FastAPI and Pydantic models.
Introduction: Documentation Machines Can Read
Python is dynamically typed: variables can hold any type at runtime. Type hints add optional annotations that describe intent:
def top_k_chunks(
query: str,
chunks: list[dict[str, str | float]],
k: int = 5,
) -> list[dict[str, str | float]]:
return sorted(chunks, key=lambda c: c["score"], reverse=True)[:k]
The signature documents that query is a string, chunks is a list of dicts with string or float values, and the function returns the same shape of list.
| Annotation | Meaning |
|---|---|
str, int, float, bool | Primitive types |
list[T] | List of items of type T |
dict[K, V] | Dictionary key and value types |
str | None | Optional string (Python 3.10+ union syntax) |
-> None | Function returns nothing useful |
Type Hints in AI Services
from pydantic import BaseModel
class PredictRequest(BaseModel):
text: str
max_tokens: int = 256
class PredictResponse(BaseModel):
label: str
confidence: float
@app.post("/predict")
def predict(body: PredictRequest) -> PredictResponse:
...
Pydantic validates incoming JSON against typed models at runtime—bridging static hints and actual enforcement.
Reality: Python ignores hints at runtime unless you use a validator (Pydantic) or a static checker (mypy). You can still pass wrong types; tools help you catch mistakes earlier.
Static Checking
# Install: pip install mypy
# Run: mypy src/
def embed(text: str) -> list[float]:
return [0.1, 0.2] # OK
embed(42) # mypy flags: Argument 1 has incompatible type "int"; expected "str"
Knowledge Check
- Write: Annotate a function taking
path: strand returninglist[str]. Answer:def read_lines(path: str) -> list[str]: - True/False: Type hints are enforced by CPython by default. Answer: False.
- Short Answer: What does
str | Nonemean? Answer: Either a string or None. - True/False: Type hints document expected shapes for humans and tooling. Answer: True.
- Short Answer: What does
list[str]mean? Answer: A list whose items are strings. - Multiple Choice: Pydantic models in FastAPI mainly: (a) ignore types, (b) validate JSON at runtime, (c) train GPUs, (d) replace pip. Answer: (b).
- True/False:
mypy/ Pyright check types statically without running the program. Answer: True. - Short Answer: What does
-> Noneon a function mean? Answer: The function returns nothing useful (None). - Multiple Choice:
dict[str, int]describes: (a) string keys and int values, (b) int keys only, (c) a list, (d) a tensor. Answer: (a). - Short Answer: Name two typing tools mentioned for AI utility modules. Answer: mypy and Pyright (Optional/Union/TypedDict also acceptable as typing constructs).
Key Takeaways
- Type hints document expected shapes for humans and tooling.
- Use modern syntax:
list[str],str | None. - FastAPI/Pydantic leverage hints for validation and OpenAPI docs.
- Next: Async / Await for concurrent I/O-bound AI workloads.
Gradual typing: Pick one utility module, add hints, run mypy. Fix three intentional bugs the checker catches.
Recap: Type hints document shapes for humans, mypy, and FastAPI/Pydantic; next, concurrent I/O in Async / Await (asyncio).