Python运行时获取任意层级泛型父类类型参数的方案咨询
鲁棒实现方案
核心思路是遍历继承链的同时维护类型变量到实际值的映射表,逐层替换泛型参数,最终得到目标父类的实际类型参数:
import typing from dataclasses import dataclass from typing import Optional, Any, TypeVar, Generic, get_origin, get_args T = TypeVar('T') @dataclass(frozen=True) class Found: value: Any def get_generic_parent_args(target_parent: type, cls: Any) -> Optional[Found]: # 处理参数化泛型输入,比如Child3[int]的情况 type_map = {} current_cls = cls origin_cls = get_origin(cls) if origin_cls is not None: # 提取最外层的泛型参数绑定 type_params = origin_cls.__parameters__ type_args = get_args(cls) type_map = {param: arg for param, arg in zip(type_params, type_args)} current_cls = origin_cls # 遍历MRO继承链 for base in current_cls.mro(): if base == target_parent: break # 遍历当前类的原始泛型基类 for orig_base in getattr(base, "__orig_bases__", ()): base_origin = get_origin(orig_base) if base_origin is None: continue # 替换当前基类参数中的类型变量 def replace_type_vars(t: Any) -> Any: if isinstance(t, TypeVar): return type_map.get(t, t) args = get_args(t) if not args: return t replaced_args = tuple(replace_type_vars(arg) for arg in args) return get_origin(t)[replaced_args] replaced_base_args = tuple(replace_type_vars(arg) for arg in get_args(orig_base)) # 找到目标父类,返回替换后的参数 if base_origin is target_parent: return Found(replaced_base_args[0] if len(replaced_base_args) == 1 else replaced_base_args) # 基类是泛型类,更新类型映射表,继续向下遍历 if hasattr(base_origin, "__parameters__"): for param, arg in zip(base_origin.__parameters__, replaced_base_args): type_map[param] = arg return None
测试验证
可直接覆盖所有需求场景:
# 基础定义 class Parent(Generic[T]): pass # 多层继承场景 class Child1(Parent[int]): pass class Child2(Child1): pass print(get_generic_parent_args(Parent, Child2)) # Found(value=<class 'int'>) # 泛型子类场景 class Child3(Parent[T], Generic[T]): pass print(get_generic_parent_args(Parent, Child3[int])) # Found(value=<class 'int'>) # 嵌套泛型场景 from typing import Sequence class Child4(Parent[Sequence[T]], Generic[T]): pass print(get_generic_parent_args(Parent, Child4[int])) # Found(value=typing.Sequence[int]) # OpenAPI业务场景 from dataclasses import dataclass from typing import ClassVar, Union @dataclass class Data: hello: str @dataclass class Error: detail: str class ClientResponse(Generic[T]): status_code: ClassVar[int] body: T class OkResponse(ClientResponse[Data]): status_code: ClassVar[int] = 200 class BadResponse(ClientResponse[Error]): status_code: ClassVar[int] = 400 print(get_generic_parent_args(ClientResponse, OkResponse)) # Found(value=<class '__main__.Data'>) print(get_generic_parent_args(ClientResponse, BadResponse)) # Found(value=<class '__main__.Error'>)
内容的提问来源于stack exchange,提问作者Mario Ishac
相关产品推荐
相关产品推荐

