【问题标题】:Get generic type of class at runtime with Python 3.6使用 Python 3.6 在运行时获取类的泛型类型
【发布时间】:2021-12-14 02:16:44
【问题描述】:

遵循此问题中描述的解决方案:How to access the type arguments of 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 无论如何都不支持数据类。不过,仍然对普通类的解决方案感兴趣。

标签: python generics


【解决方案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 安装为库,尽管它不是此问题的一部分。另请注意,__args__ 在 Python 3.6 中似乎没有记录,并从 Python 3.8 中删除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多