Defining sub-classes of generic classes

User-defined generic classes and generic classes defined in typingcan be used as base classes for another classes, both generic andnon-generic. For example:

  1. from typing import Generic, TypeVar, Mapping, Iterator, Dict
  2.  
  3. KT = TypeVar('KT')
  4. VT = TypeVar('VT')
  5.  
  6. class MyMap(Mapping[KT, VT]): # This is a generic subclass of Mapping
  7. def __getitem__(self, k: KT) -> VT:
  8. ... # Implementations omitted
  9. def __iter__(self) -> Iterator[KT]:
  10. ...
  11. def __len__(self) -> int:
  12. ...
  13.  
  14. items: MyMap[str, int] # Okay
  15.  
  16. class StrDict(Dict[str, str]): # This is a non-generic subclass of Dict
  17. def __str__(self) -> str:
  18. return 'StrDict({})'.format(super().__str__())
  19.  
  20. data: StrDict[int, int] # Error! StrDict is not generic
  21. data2: StrDict # OK
  22.  
  23. class Receiver(Generic[T]):
  24. def accept(self, value: T) -> None:
  25. ...
  26.  
  27. class AdvancedReceiver(Receiver[T]):
  28. ...

Note

You have to add an explicit Mapping base classif you want mypy to consider a user-defined class as a mapping (andSequence for sequences, etc.). This is because mypy doesn’t usestructural subtyping for these ABCs, unlike simpler protocolslike Iterable, which use structural subtyping.

Generic can be omitted from bases if there areother base classes that include type variables, such as Mapping[KT, VT]in the above example. If you include Generic[…] in bases, thenit should list all type variables present in other bases (or more,if needed). The order of type variables is defined by the followingrules:

  • If Generic[…] is present, then the order of variables isalways determined by their order in Generic[…].
  • If there are no Generic[…] in bases, then all type variablesare collected in the lexicographic order (i.e. by first appearance).

For example:

  1. from typing import Generic, TypeVar, Any
  2.  
  3. T = TypeVar('T')
  4. S = TypeVar('S')
  5. U = TypeVar('U')
  6.  
  7. class One(Generic[T]): ...
  8. class Another(Generic[T]): ...
  9.  
  10. class First(One[T], Another[S]): ...
  11. class Second(One[T], Another[S], Generic[S, U, T]): ...
  12.  
  13. x: First[int, str] # Here T is bound to int, S is bound to str
  14. y: Second[int, str, Any] # Here T is Any, S is int, and U is str