Python 3.6如何在运行时获取类的泛型类型

4

根据这个问题描述的解决方案:如何访问typing.Generic的类型参数?

我已经成功地在Python 3.8中运行了泛型类型。但是,我似乎无法访问解决方案中针对Python 3.6描述的__args__字段。我不确定原因,这是我的代码:

def get_generic_type_arg(cls):
    if py_version >= (3, 8):
        t = cls.__orig_bases__[0]
        return get_args(t)[0]
    else:
        t = cls.__args__
        return None

class EventContract:
    @classmethod
    def get_version(cls) -> int:
        return int(cls.__name__[1:])


RT = TypeVar('RT', bound=EventContract)


class QueryContract(Generic[RT], EventContract):
    """ Base class for query contracts that are versioned. """

    @classmethod  # Do not override this
    def get_response_class(cls) -> Type[RT]:
        return get_generic_type_arg(cls)

    def build_result(self, *args, **kwargs):
        return self.get_response_class()(**kwargs)


@dataclasses.dataclass
class V1Response(EventContract):
    value: int


@dataclasses.dataclass
class V1(QueryContract[V1Response]):
    id: int
    name: str


尝试在cls上调用get_generic_type时,我收到了AttributeError。 我还尝试使用t.__bases__ [0]获取其基类,它给我带来没有泛型参数的QueryContract(__args__给我另一个属性错误)。 我正在对V1调用get_response_class方法。 有什么想法吗?

我已经意识到Python 3.6无论如何都不支持数据类。尽管如此,我仍然对使用普通类的解决方案感兴趣。 - BinarSkugga
1个回答

1

我已经找出如何做了。因为某种原因,__orig_bases__没有起作用,但在重新构建我的Python 3.6和使用VENV之后,它可以工作了。这是最终的可行方法:

py_version = sys.version_info
if py_version >= (3, 8):
    from typing import get_args


def get_generic_type_arg(cls):
    t = cls.__orig_bases__[0]
    if py_version >= (3, 8):
        return get_args(t)[0]
    else:
        return t.__args__[0]

Python 3.6还需要安装dataclasses库,尽管它不是这个问题的一部分。另外请注意,在Python 3.6中,__args__似乎没有文档记录,并在Python 3.8中被删除。


1
感觉太低级了,如果我需要这种程度的内省,并且它没有通过稳定的语言外观支持,我宁愿将我的类型作为普通变量传递。 - matanster

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