Skip to content

Runtime vs Static

Python typing lives in two different worlds at once: the static world of type checkers and the runtime world of frameworks that inspect annotations directly. If you blur those worlds together, `Annotated`, deferred annotations, FastAPI, and Pydantic quickly become confusing.

Quick takeaway: type checkers read annotations for static meaning, while runtime tools read annotations as objects or expressions they can inspect. `Annotated` and `annotationlib` are especially important at this boundary.

Separate the Two Views

The same annotation serves different consumers: static analyzers and runtime frameworks do not use it for the same purpose.

A Small Example

py
from typing import Annotated

import annotationlib


def endpoint(
    user_id: Annotated[int, "path parameter"],
) -> Annotated[str, "response body"]:
    return str(user_id)


print(
    annotationlib.get_annotations(
        endpoint,
        format=annotationlib.Format.STRING,
    )
)
print(endpoint.__annotations__)

A type checker mainly cares about `int` and `str`. Runtime tools can also inspect metadata inside `Annotated` and can work with deferred annotation forms through `annotationlib`.

What FastAPI and Pydantic Consume

  • FastAPI reads parameter annotations and Annotated metadata to build request parsing and OpenAPI descriptions.
  • Pydantic reads annotations to build core schema for validation and serialization.
  • So annotations are no longer just static comments for tooling.

Key Questions

  • Why do type checkers know things the runtime does not?
  • Which parts of an annotation are types and which parts are metadata?

Checklist

Separate static and runtime meaning

Type checkers infer without executing code; frameworks read annotation objects at runtime.

Use `Annotated` intentionally

It is a strong tool for carrying both type meaning and runtime metadata, but the two roles should stay conceptually separate.

Understand annotation reading cost

Deferred annotations and `annotationlib` exist partly to reduce forward-reference and import-cycle pain.

Know how frameworks consume annotations

FastAPI, Pydantic, and ORMs can treat annotations as runtime metadata, not just type hints.

Official Sources

Built with VitePress for a Python 3.14 handbook.