3

I have a generic parent class and a child class that implements the parent with a specific type:

T = TypeVar("T")

class Parent(ABC, Generic[T]):
    def get_impl_t(self):
        pass

class Child(Parent[int]):
    pass

I'd like to get the type of the child class from the parent (see get_impl_t()).

I'm pretty sure this isn't possible without some hackery (inspect.getsource()?) because of type erasure. It's wouldn't work if this didn't have a class hierarchy.

The obvious workaround is add an abstract classmethod that gets the type or add a parameter to the parent class's constructor:

class Parent(ABC, Generic[T]):
    def__init__(self, param_cls: Type[T]) -> None:
        self.param_cls = param_cls

    # or
    @classmethod
    @abstractmethod
    def get_param_cls() -> Type[T]:
        pass

This would add some maintenance overhead, so I want to make sure I'm not missing anything.

1
  • I think I want to parse the result of Child.__orig_bases__ Commented May 7, 2022 at 3:27

1 Answer 1

3

You could use typing.get_origin and typing.get_args. So, something to the effect of:

def get_impl_t(self):
    for type_ in type(self).__orig_bases__:
        if typing.get_origin(type_) is Parent:
            return typing.get_args(type_)[0]
             

How exactly you want to handle things is going to depend on the particulars of your use-case. But here's a demo:

In [1]: import typing

In [2]: from typing import TypeVar, Generic

In [3]: T = TypeVar("T")
   ...:
   ...: class Parent(Generic[T]):
   ...:     def get_impl_t(self):
   ...:         for type_ in type(self).__orig_bases__:
   ...:             if typing.get_origin(type_) is Parent:
   ...:                 return typing.get_args(type_)[0]
   ...:
   ...: class Child(Parent[int]):
   ...:     pass
   ...:

In [4]: Child().get_impl_t()
Out[4]: int

And with another child:

In [5]: class AnotherChild(Parent[str]):
   ...:     pass
   ...:

In [6]: AnotherChild().get_impl_t()
Out[6]: str
Sign up to request clarification or add additional context in comments.

1 Comment

If you have an additional inheriting class, I think the type check needs to be different. i.e. class Child(Parent[T]): pass class GrandChild(Parent[int]): pass In this case I think we want: if issubclass(typing.get_origin(type_), Parent)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.