如何在Python中获取子类的泛型类型

3

我有一个通用的父类,还有一个子类,它使用特定类型来实现父类:

T = TypeVar("T")

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

class Child(Parent[int]):
    pass

我希望能够从父类获取子类的类型(请参见get_impl_t())。

由于类型抹消,我相当确定这是不可能的,除非进行一些hackery(inspect.getsource()?)。如果没有类层次结构,这不起作用。

明显的解决方法是添加一个抽象的classmethod来获取类型,或者将参数添加到父类的构造函数中:

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

这样做会增加一些维护开销,所以我想确保我没有漏掉任何东西。


我认为我想解析Child.__orig_bases__的结果。 - David Ehrmann
1个回答

3
你可以使用 typing.get_origintyping.get_args。因此,类似以下的内容:
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]
             

具体如何处理事情将取决于您的用例的特定情况。但这里有一个演示:

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

再添加一个子元素:

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

In [6]: AnotherChild().get_impl_t()
Out[6]: str

如果您有一个额外的继承类,我认为类型检查需要不同。例如:
class Child(Parent[T]): pass class GrandChild(Parent[int]): pass 在这种情况下,我认为我们需要:
if issubclass(typing.get_origin(type_), Parent)
- Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接