PEP 695 in 90 seconds — generic types without TypeVar
Generic functions and classes, finally readable.
The old way to write a generic function in Python: ```python from typing import TypeVar T = TypeVar("T") def first(items: list[T]) -> T: return items[0] ``` Three places to look. An import, a module-scoped binding, then the actual signature.
PEP 695 (Python 3.12, 2023) put the type parameter where it belongs — inline: ```python def first[T](items: list[T]) -> T: return items[0] ``` No import. No module-scoped TypeVar. The `[T]` between the function name and the params declares the type variable for THIS function only. Generic classes get the same treatment: `class Stack[T]:`. Runtime behaviour is identical to the old way — this is a syntax win, not a feature change. But it's a big enough syntax win that mypy + pyright + Pydantic v2 all support both.
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
class Stack(Generic[T]):
def __init__(self) -> None:
self._data: list[T] = []# No import needed
def first[T](items: list[T]) -> T:
return items[0]
class Stack[T]:
def __init__(self) -> None:
self._data: list[T] = []🎯 Predict the output
What does this print? (PEP 695 is syntax — runtime behaviour is identical to TypeVar.)
def last[T](items: list[T]) -> T:
return items[-1]
print(last([1, 2, 3]))
print(last(["a", "b", "c"]))