Generic Classes with class Stack[T]

Write containers that stay type-safe for any element type using Python 3.12+ generic syntax.

A generic class works with any type while keeping the type checker informed of exactly which one you chose. A Stack of int and a Stack of str share one implementation but never get confused for each other.

The modern syntax (Python 3.12+)

Since Python 3.12, you declare a type parameter right in the class header — no more importing TypeVar and inheriting from Generic:

class Stack[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()

numbers: Stack[int] = Stack()
numbers.push(1)      # a type checker now knows pop() returns int

Why it matters

At runtime the type parameter is essentially erased — your code runs the same. The payoff is at authoring time: your editor autocompletes correctly, and a checker like mypy flags numbers.push('oops') before you ever run the program. Generics are how you get the flexibility of duck typing with the safety net of static types.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A typed Stack[int] ensures only integers are pushed, catching misuse at static analysis time.
  • A generic Result[T] class wraps a success value or an error message while preserving the value type.
  • A typed Queue[Task] makes it clear what objects can be enqueued and dequeued in a worker pool.

More examples

Generic Stack with class[T]

Defines a generic Stack using Python 3.12+ class[T] syntax that preserves the element type.

Example · python
class Stack[T]:
    def __init__(self): self._items: list[T] = []
    def push(self, item: T) -> None: self._items.append(item)
    def pop(self) -> T: return self._items.pop()
    def __len__(self) -> int: return len(self._items)

s: Stack[int] = Stack()
s.push(1)
s.push(2)
print(s.pop())   # 2

Generic Pair class

Uses two type parameters A and B to create a strongly-typed pair with a type-aware swap method.

Example · python
class Pair[A, B]:
    def __init__(self, first: A, second: B):
        self.first = first
        self.second = second
    def swap(self) -> 'Pair[B, A]':
        return Pair(self.second, self.first)

p = Pair('hello', 42)
print(p.first, p.second)    # hello 42
swapped = p.swap()
print(swapped.first)         # 42

Generic class with TypeVar (3.11 compat)

Provides the pre-3.12 approach using TypeVar and Generic[T] for backwards-compatible generic classes.

Example · python
from typing import Generic, TypeVar

T = TypeVar('T')

class Box(Generic[T]):
    def __init__(self, value: T): self.value = value
    def unwrap(self) -> T: return self.value

box: Box[str] = Box('treasure')
print(box.unwrap())   # treasure

Discussion

  • Be the first to comment on this lesson.