`typing` — Advanced Type Annotations
Python · Standard Library · Run with python3
Explanation
The `typing` module provides building blocks for complex type annotations. `TypeVar` and `Generic` enable generic classes. `Protocol` defines structural subtyping (duck typing made explicit). `TypedDict` types `dict` literals with known keys. `Literal` restricts a type to specific values. `Union` / `|` union types. `Optional[X]` = `X | None`. `cast()` tells the type checker to treat a value as a specific type (no runtime effect). `TYPE_CHECKING` guards imports that are only needed for type checking.
Real-World Scenario
A plugin system uses `Protocol` to define the interface plugins must satisfy: `class Plugin(Protocol): def run(self, context: Context) -> Result: ...`. Any class with a matching `run` method satisfies the protocol — no explicit inheritance required. `mypy` catches missing methods at type-check time. ```python from typing import TypeVar, Generic, Protocol, TypedDict, Literal, TYPE_CHECKING from collections.abc import Iterator if TYPE_CHECKING: pass # Only imported for type checks — avoids circular imports T = TypeVar("T") S = TypeVar("S", bound="Comparable") class Comparable(Protocol): def __lt__(self: S, other: S) -> bool: ... def minimum(items: list[S]) -> S: return min(items) class Stack(Generic[T]): def __init__(self) -> None: self._items: list[T] = [] def push(self, item: T) -> None: self._items.append(item) def pop(self) -> T: return self._items.pop() def __iter__(self) -> Iterator[T]: return iter(self._items) class UserConfig(TypedDict): name: str role: Literal["admin", "user", "guest"] active: bool cfg: UserConfig = {"name": "Alice", "role": "admin", "active": True} print(minimum([3, 1, 4, 1, 5])) # 1 ```
Quick Snippet
from typing import TypeVar, Generic, Protocol, TypedDict, Literal, TYPE_CHECKING
from collections.abc import Iterator
if TYPE_CHECKING:
pass # Only imported for type checks — avoids circular imports
T = TypeVar("T")
S = TypeVar("S", bound="Comparable")
class Comparable(Protocol):
def __lt__(self: S, other: S) -> bool: ...
def minimum(items: list[S]) -> S:
return min(items)
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None: self._items.append(item)
def pop(self) -> T: return self._items.pop()
def __iter__(self) -> Iterator[T]: return iter(self._items)
class UserConfig(TypedDict):
name: str
role: Literal["admin", "user", "guest"]
active: bool
cfg: UserConfig = {"name": "Alice", "role": "admin", "active": True}
print(minimum([3, 1, 4, 1, 5])) # 1Full Example
# Compile: python3 typing_advanced.py
# Output:
# 1
# [1, 2, 3]
from typing import TypeVar, Generic, Protocol, TypedDict, Literal, runtime_checkable
from collections.abc import Iterator
T = TypeVar("T")
S = TypeVar("S", bound="Orderable")
@runtime_checkable
class Orderable(Protocol):
def __lt__(self: S, other: S) -> bool: ...
def minimum(items: list[S]) -> S:
return min(items)
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None: self._items.append(item)
def pop(self) -> T: return self._items.pop()
def __iter__(self) -> Iterator[T]: return iter(self._items)
def __len__(self) -> int: return len(self._items)
class UserConfig(TypedDict):
name: str
role: Literal["admin", "user", "guest"]
active: bool
cfg: UserConfig = {"name": "Alice", "role": "admin", "active": True}
print(cfg["name"])
stack: Stack[int] = Stack()
for n in [1, 2, 3]:
stack.push(n)
print(list(stack))
print(minimum([3, 1, 4, 1, 5]))
# isinstance check via runtime_checkable Protocol
print(isinstance(42, Orderable)) # True (int has __lt__)
print(isinstance("hi", Orderable)) # True (str has __lt__)
python3 typing_advanced.py