TypeVar and Generic Functions

RoadmapsPython

Overview

A `TypeVar` creates a generic function that adapts its return type based on the input type. By using a placeholder like `T`, you tell the type checker to track the specific type passing through the function. def get_first(items: list[T]) -> T: return items[0] Whatever type `T` is in the input list, that exact same type `T` will be returned. If you pass a `list[int]`, `T` becomes `int`, preserving full IDE autocomplete. # Python 3.12+ syntax def get_first[T](items: list[T]) -> T: return items[0] In Python 3.12+, you can skip the `TypeVar` import and declare the generic parameter directly in square brackets. def choose[T](a: T, b: T) -> T: return a # Trap: Conflicting types for the same TypeVar val = choose(1, "apple") When multiple arguments share the same `TypeVar`, passing different types forces the type checker to resolve a common base class or union. This can accidentally weaken your type safety if you expected strict matching.

Without `TypeVar`, you'd have to use `Any` or `Union` for a function that works on many types, but that destroys autocomplete. `TypeVar` preserves the exact type information passing *through* the function.

Where used: Utility functions like `first_or_default`, Decorators that preserve the decorated function's signature

Why learn this

Code walkthrough

from typing import TypeVar

T = TypeVar('T')

def get_last(items: list[T]) -> T:
  return items[-1]

number = get_last([1, 2, 3])
text = get_last(['a', 'b', 'c'])
print(f'{number}, {text}')

Focus: def get_last(items: list[T]) -> T:

Aha moment

from typing import TypeVar
T = TypeVar('T')
print(type(T))

Prediction: What does this print?

Common guess: It prints something like `<class 'type'>` or it fails because `T` isn't a real class.

It prints `<class 'typing.TypeVar'>`. `TypeVar` is just an object created at runtime to hold metadata for static analysis tools; it has no magical behavior when the program executes.

Common mistakes

Glossary

generic function
A function designed to work with various data types while still keeping track of the specific type being used. Example: `def get_first[T](items: list[T]) -> T:`.
placeholder
A temporary symbol or variable (like `T`) that stands in for an actual, concrete data type until the function is called. Example: `T = TypeVar('T')`.

Recall questions

Understanding checks

Why will a static type checker complain about this function?

The return type says it will return a list of `T` (the exact type passed in), but the function body forces the items to be strings.

The promise of `T` is that the output type matches the input type. If the input is an `int`, it promises a `list[int]`, but actually returns a `list[str]`.

In `def identity[T](value: T) -> T:`, what type is `T` when you call `identity(42)`?

`T` resolves to `int`.

The type checker infers the concrete type of `T` based on the argument provided at the call site.

Practice tasks

Use a `TypeVar`

Given this working code, replace the `Any` type hints with a `TypeVar` named `T` so the type checker knows the return type matches the input type.

Continue learning

Previous: Generic Types

Return to Python Roadmap