pythongenericspython-typing

Python Type Hinting: Subclass not compatible with generic


I have the following simple classes

class A:
    pass

class B(A):
    pass

I want another class, C, with a method which will accept as an argument any subclass of A, which will default to B. I thought a Generic would be a suitable candidate here:

T = TypeVar('T', bound=A)


class C(Generic[T]):
    def foo(self, assistant: type[T] = B) -> None:
        pass

However, when I run mypy I get the error

Incompatible default for argument "assistant" (default has type "type[B]", argument has type "type[T]"

I find this a little confusing, as I thought the idea of TypeVar('T', bound=A) was to create a type compatible with any subclass of A (so in particular B).

Does anyone know what I'm doing wrong here?


Solution

  • You don't need generics. You should just do

    class C:
        def foo(self, assistant: type[A] = B) -> None:
            ...
    

    type[A] is already the type representing all classes that descend from A (including A).

    What you've done is create a generic class. That class takes type parameters, like c: C[B] = C(), and the argument to foo must be a descendant of whatever the type parameter was.

    With your class definition, if you did

    class D(A): pass
    
    c: C[D] = C()
    

    then c.foo would require a descendant of D as an argument. However, the default value B is not a descendant of D, so the default value would be an invalid argument, hence the error message.