Friday, 9 December 2022

Changing type argument of Python with subclassing

Python's typing system allows for generics in classes:

class A(Generic[T]):
    def get_next(self) -> T

which is very handy. However, even in 3.11 with the Self type, I cannot find a way to change the type argument (the T) without specifying the class name. Here's the recommended usage from PEP 673: Self Type: https://peps.python.org/pep-0673/a

class Container(Generic[T]):
    def foo(
        self: Container[T],
    ) -> Container[str]:
        # maybe implementing something like:
        return self.__class__([str(x) for x in self])

The problem is if I want to subclass container:

class SuperContainer(Container[T]):
    def time_travel(self): ...

And then if I have an instance of SuperContainer and call foo on it, the typing will be wrong, and think that it's a Container not SuperContainer.

sc = SuperContainer([1, 2, 3])
sc2 = sc.foo()
reveal_type(sc2)  # mypy: Container[str]
sc2.time_travel()  # typing error: only SuperContainers can time-travel
isinstance(sc2, SuperContainer)  # True

Is there an accepted way to allow a program to change the type argument in the superclass that preserves the typing of the subclass?



from Changing type argument of Python with subclassing

No comments:

Post a Comment