Skip to main content
A type parameter is a placeholder variable evaluated during static type checking that represents a type rather than a runtime data value. It forms the foundational mechanism for generic programming in Python, allowing functions, classes, and type aliases to be parameterized over one or more types while preserving strict type annotations and static type safety.

Modern Syntax (Python 3.12+)

PEP 695 introduced a native syntax for type parameters using square brackets [...] directly in the definition signature. This syntax automatically scopes the type parameter to the defined entity.

Legacy Syntax (Python 3.11 and earlier)

Prior to Python 3.12, type parameters are instantiated as objects in the global scope using the typing.TypeVar constructor, and classes must inherit from typing.Generic.

Type Parameter Mechanics

1. Bounds

A bound restricts the type parameter to a specific class or its subclasses. The static type checker will reject any type argument that does not satisfy the issubclass() relationship with the bound.
  • Modern Syntax: [T: BaseClass]
  • Legacy Syntax: T = TypeVar('T', bound=BaseClass)

2. Constraints

Constraints restrict the type parameter to a strict, finite set of allowed types. Static type checkers do allow subclasses of constrained types to be passed as arguments. However, unlike bounds (which preserve the specific subclass type), constraints resolve and bind the type variable to the exact constrained base type rather than the subclass.
  • Modern Syntax: [T: (TypeA, TypeB)]
  • Legacy Syntax: T = TypeVar('T', TypeA, TypeB)

3. Variance

Variance defines how subtyping rules apply to the generic type containing the type parameter.
  • Invariant: Generic[Child] is not a subtype of Generic[Parent].
  • Covariant: Generic[Child] is a subtype of Generic[Parent].
  • Contravariant: Generic[Parent] is a subtype of Generic[Child].
Under the modern Python 3.12+ syntax, variance is automatically inferred by static type checkers based on how the type parameter is utilized within the class body. In the legacy syntax, variance must be explicitly declared using boolean flags:

4. Defaults (Python 3.13+)

PEP 696 introduces the ability to assign default types to type parameters. If a type argument is omitted during instantiation, the static type checker falls back to the default.
  • Syntax: [T = DefaultType]

5. Specialized Type Parameters

Standard type parameters (TypeVar) represent a single type. Python provides two additional type parameter constructs for complex signatures:
  • ParamSpec: Captures the parameter types (the argument signature) of a callable. The return type must be captured separately using a standard TypeVar. Denoted by ** in modern syntax.
  • TypeVarTuple: Captures an arbitrary number of types, enabling variadic generics. Denoted by * in modern syntax.
Tired of Poor Python Skills? Fix That With Deep Grasping!Learn More