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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.