Search code examples
pythongenericsfastapimultiple-inheritancemetaclass

How to make generic class inheriting from TypeVar in Python?


How can I create a Generic class in Python, that has the TypeVar as a base class?

The minimum example is this:

from typing import TypeVar, Generic

T = TypeVar("T")

class A(T, Generic[T]):
    pass

Unfortunately, it gives me the following error:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

A bit of context: the reason I want to do do this, is since I want my derived class A to have all the fields of T, so that to have these fields annotated in T and I want the resulting instance of A to have those fields, as that will serve as the type as a response in my REST server with FastAPI.


Solution

  • The normal thing to resolve a "metaclass conflict" is to pick the metaclasses (the type) of the conflicting bases - in this case type(T) and type(Generic[T])), and create a derived metaclass from them.

    However, typing classes are rather customized and not regular Python classes for use at runtime: in special, one can't derive a subclass from them. So building a compatible metaclass that would allow you to do what you describe is not possible.

    Inheriting from a single typevar is also not possible, and does not make sense at all: Typing information is just pre-compiler annotations, so that special tools can verify no one is passing invalid data to a function or method.

    FastAPI uses annotations in a concrete, runtime, manner: it can't deal with "generics": it has to know the concrete type of fields that will be part of a model. If you want to have dynamic classes with fields that will only be known at runtime, you can do that, but with plain, very concrete and definite, Python code, not with Generics.

    That said, you will likely find a way to do what you intend to by using typing.Protocol instead of generics: that way you can indicate that a class has "at least these members and methods".