Python __class_getitem__ Method

Complete guide to Python's __class_getitem__ method covering type hints, generics, and custom container types.

Python __class_getitem__ Method

Python class_getitem Method

Last modified April 8, 2025

This comprehensive guide explores Python’s class_getitem method, introduced in PEP 560 for type hinting and generic class support. We’ll cover basic usage, type hints, generics, and practical examples.

Basic Definitions

The class_getitem method allows classes to support subscription notation (square brackets) for type hinting purposes. It’s called when using Class[item] syntax.

Key characteristics: it’s a class method (though not decorated as such), receives the class as first argument, and returns a specialized version of the class. It enables generic type annotations without runtime type checking.

Basic class_getitem Implementation

Here’s a simple implementation showing how class_getitem works. This demonstrates the basic syntax and behavior of the method.

basic_class_getitem.py

class GenericBox: def class_getitem(cls, item): print(f"Creating GenericBox specialized for {item}") return f"GenericBox[{item.name}]"

print(GenericBox[int]) # GenericBox[int] print(GenericBox[str]) # GenericBox[str]

This example shows how class_getitem intercepts the square bracket notation. When GenericBox[int] is called, it invokes class_getitem with int as the item.

The method returns a string here for demonstration, but in real usage it would typically return a specialized version of the class or a typing._GenericAlias.

Type Hinting with class_getitem

class_getitem is primarily used to support type hints in Python. Here’s how to implement it for custom container types.

type_hinting.py

from typing import Any, TypeVar, Generic

T = TypeVar(‘T’)

class Box(Generic[T]): def init(self, content: T): self.content = content

@classmethod
def __class_getitem__(cls, item):
    return super().__class_getitem__(item)

def __repr__(self):
    return f"Box({self.content!r})"

Type hints work with the custom container

def process_box(box: Box[int]) -> int: return box.content * 2

box = Box(42) print(process_box(box))

This example shows a generic Box class that can be parameterized with types. The class_getitem implementation delegates to the parent Generic class to handle type parameterization correctly.

The type checker will understand Box[int] as a box containing integers, while at runtime it returns a typing._GenericAlias instance.

Custom Generic Class

You can create your own generic classes without inheriting from typing.Generic by implementing class_getitem.

custom_generic.py

class Pair: def init(self, first, second): self.first = first self.second = second

def __class_getitem__(cls, items):
    if not isinstance(items, tuple):
        items = (items,)
    if len(items) != 2:
        raise TypeError("Pair requires exactly two type arguments")
    
    first_type, second_type = items
    return type(f"Pair[{first_type.__name__}, {second_type.__name__}]",
               (cls,),
               {'__annotations__': {'first': first_type, 'second': second_type}})

def __repr__(self):
    return f"Pair({self.first!r}, {self.second!r})"

IntStrPair = Pair[int, str] pair = IntStrPair(42, “answer”) print(pair) # Pair(42, ‘answer’)

This custom Pair class implements its own generic type support. The class_getitem method creates a new subclass with type annotations based on the provided type arguments.

At runtime, Pair[int, str] creates a new class with appropriate type annotations, which type checkers can use for static type checking.

Runtime Type Checking

While class_getitem is mainly for type hints, you can combine it with runtime type checking for more robust code.

runtime_checking.py

class CheckedList: def init(self, items): self.items = list(items)

def __class_getitem__(cls, item_type):
    class CheckedListSubclass(cls):
        def append(self, item):
            if not isinstance(item, item_type):
                raise TypeError(f"Expected {item_type.__name__}, got {type(item).__name__}")
            super().append(item)
    return CheckedListSubclass

def append(self, item):
    self.items.append(item)

IntList = CheckedList[int] numbers = IntList([1, 2, 3]) numbers.append(4)

numbers.append(“four”) # Raises TypeError

This example creates a type-checked list that verifies items match the specified type at runtime. The class_getitem method creates a subclass with runtime type checking.

When CheckedList[int] is called, it returns a subclass that validates all appended items are integers. This combines static type hints with runtime validation.

Forward References and String Literals

class_getitem can handle forward references using string literals, which is useful for type hints that reference not-yet-defined types.

forward_refs.py

class Node: def class_getitem(cls, item): if isinstance(item, str): # Handle forward references return f"Node[’{item}’]" return f"Node[{item.name}]"

class Tree: pass

Using forward reference

print(Node[“Tree”]) # Node[‘Tree’]

Using actual type

print(Node[Tree]) # Node[Tree]

This example demonstrates how class_getitem can handle both actual types and string literals. String literals are used for forward references in type hints.

Type checkers will recognize this pattern and properly handle forward references in type annotations, while at runtime it just returns a formatted string.

Best Practices

  • Type hints first: Main purpose is type hinting, not runtime behavior

  • Consistent returns: Return typing._GenericAlias for compatibility

  • Forward references: Support string literals for forward references

  • Document behavior: Clearly document any special type handling

  • Performance: Cache created generic types if performance is critical

Source References

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.

ad ad