zyxue
zyxue

Reputation: 8888

How to type an argument which will be subclassed in Python

I have a piece that follows such pattern

from typing import Any


class Base:
    ...


class Derived1(Base):
    ...


class Derived2(Base):
    ...


class BasicApp:
    # how to type d in this base class?
    def handle(self, d: Base) -> None:
        print("handle from BasicApp", d)


class AppX(BasicApp):
    def handle(self, d: Derived1) -> None:
        print("handle from AppX", d)


class AppY(BasicApp):
    def handle(self, d: Derived2) -> None:
        print("handle from AppY", d)

I'm not sure what's the right way to type d in BasicApp.d.

I tried d: Base, then

error: Argument 1 of "handle" is incompatible with supertype "BasicApp"; supertype defines the argument type as "Base"

I tried T = TypeVar('T', bound=Base) and d: T, then

error: Argument 1 of "handle" is incompatible with supertype "BasicApp"; supertype defines the argument type as "T"

What's the right way?

Upvotes: 0

Views: 98

Answers (1)

chepner
chepner

Reputation: 531708

You need to make BaseApp generic, so that the argument type for the method is effectively a "function" of the class itself.

from typing import Generic, TypeVar


class Base:
    ...


class Derived1(Base):
    ...


class Derived2(Base):
    ...


T = TypeVar("T", bound=Base)


class BasicApp(Generic[T]):
    # how to type d in this base class?
    def handle(self, d: T) -> None:
        print("handle from BasicApp", d)


class AppX(BasicApp[Derived1]):
    def handle(self, d: Derived1) -> None:
        print("handle from AppX", d)


class AppY(BasicApp[Derived2]):
    def handle(self, d: Derived2) -> None:
        print("handle from AppY", d)

Upvotes: 1

Related Questions