PEP 526 in 90 seconds — class + module-level type annotations
Annotate fields, not just function params.
PEP 484 (2015) added type hints — but only on function parameters and return values. Class fields and module-level globals had no way to declare types except via comments: ```python class Item: name = '' # type: str quantity = 0 # type: int ``` Ugly, parser-unfriendly, easy to drift. PEP 526 (Python 3.6, 2016) added the syntax we now take for granted: ```python class Item: name: str quantity: int = 0 ```
Three patterns shipped together: - **Class attribute** with type only — `name: str` (no value; signals "every instance must have this"). - **Class attribute** with type + default — `quantity: int = 0`. - **Module-level global** — `MAX_RETRIES: int = 5` at the top of a module. The runtime stores the type in `__annotations__` but doesn't enforce it (same as PEP 484). The ecosystem leans on this: `@dataclass`, Pydantic BaseModel, SQLAlchemy 2.0 ORM, msgspec, FastAPI request bodies — all read `__annotations__` to synthesise `__init__`, validation, and OpenAPI schemas.
class Inventory:
# type: comments — readable by mypy but not by the parser
name = "" # type: str
quantity = 0 # type: int
prices = None # type: dict[str, float]
def __init__(self, name):
# type: (str) -> None
self.name = name
self.prices = {}
# Module-level type-commented global:
MAX_RETRIES = 5 # type: intclass Inventory:
name: str
quantity: int = 0
prices: dict
def __init__(self, name: str):
self.name = name
self.prices = {}
# Module-level annotation
MAX_RETRIES: int = 5
# What @dataclass / Pydantic / SQLAlchemy 2.0 all leverage:
# Inventory.__annotations__ == {
# "name": str, "quantity": int, "prices": dict
# }
# Reading this dict is how those libs synthesise __init__, validators,
# and ORM column definitions automatically.🎯 Predict the output
What does this print? PEP 526 annotations are stored in `__annotations__` at runtime, but don't enforce types.
class Inventory:
name: str
quantity: int = 0
prices: dict
def __init__(self, name: str):
self.name = name
self.prices = {}
inv = Inventory("apples")
inv.prices["red"] = 1.50
inv.prices["green"] = 1.20
print(inv.name)
print(inv.quantity)
print(inv.prices)
print(sorted(Inventory.__annotations__.keys()))