Generic Types

RoadmapsPython

Overview

Generic types allow you to specify the *contents* of a container type. Instead of just saying a variable is a `list`, you say it is a `list[str]`. users: list[str] = ['alice', 'bob'] scores: dict[str, int] = {'alice': 95} For dictionaries, you specify both key and value types: `dict[str, int]`. In older Python (versions before 3.9), you had to import `List` and `Dict` from the `typing` module, but modern Python allows using the built-in lowercase types directly. def get_first(items: list) -> typing.Any: return items[0] result = get_first([1, 2, 3]) Using plain `list` in function signatures causes type erasure. To retain the inner type (e.g., returning an `int` when passing a `list[int]`), you need type variables. This is covered fully in typevar-generic-functions.

A bare `list` or `dict` annotation doesn't tell the IDE (Integrated Development Environment) or type checker what methods are safe to call on the items inside the container. Generics provide that inner visibility.

Where used: Defining nested JSON payloads in APIs, ORM query results (e.g. a `list` of models)

Why learn this

Code walkthrough

def summarize_scores(scores: dict[str, list[int]]) -> dict[str, int]:
  result = {}
  for name, num_list in scores.items():
    result[name] = sum(num_list)
  return result

print(summarize_scores({'Alice': [10, 20]}))

Focus: def summarize_scores(scores: dict[str, list[int]]) -> dict[str, int]:

Aha moment

my_list: list[int] = [1, 2, 3]
my_list.append('hello')
print(my_list)

Prediction: What does this code print?

Common guess: It raises a `TypeError` because we appended a `str` to a `list[int]`.

It prints `[1, 2, 3, 'hello']`. At runtime, Python ignores the `[int]` part entirely. The `list` is just a standard dynamic list.

Common mistakes

Glossary

static type checkers
Tools that analyze your code without running it to find potential errors related to data types. Example: running `mypy script.py` would flag `x: int = 'hello'` as a type error without executing the code.
deprecated
A feature or practice that is no longer recommended and may be removed in future versions. Example: `from typing import List` is deprecated in Python 3.9+ — use the built-in `list` instead.

Recall questions

Understanding checks

Why will a static type checker complain about this function?

The function claims to return a `list` of strings (`list[str]`), but the returned `list` contains an `int` (`42`).

Generic annotations enforce that all elements within the container match the specified inner type when analyzed by a type checker.

If you have a variable typed as `data: dict[str, int | str]`, what kinds of values are allowed in the dictionary?

The dictionary keys must be strings (`str`), and the values can be either integers (`int`) or strings (`str`).

Generic types can be composed with other type hints like Unions (`|`) to express complex allowed shapes for the container's contents.

Practice tasks

Add generic type hints

Given this working code, add generic type hints. `users` is a `list` of strings (`str`), and `roles` is a `list` of strings (`str`). The function returns a `dict` mapping a `str` to a `str`.

Challenge

Type a nested data structure

Write a function `flatten_groups` that takes a `dict` where keys are strings (group names) and values are lists of strings (member names). It should return a single flat `list` of all member names (`str`). Provide full type hints.

Continue learning

Previous: Basic Annotations

Previous: Optional and Union Types

Next: TypeVar and Generic Functions

Return to Python Roadmap