You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Python泛型子类的泛型实参?

获取泛型子类的绑定类型参数

当你直接继承一个已经绑定了类型参数的泛型实例(比如Base[int, str])时,get_args(Example2)返回空是因为Example2本身是一个具体类,不是泛型类的实例。要获取它继承时绑定的类型参数,需要访问类的__orig_bases__属性——这个属性会保存类定义时使用的原始泛型基类(包含类型参数)。

基础解决方案

直接读取__orig_bases__并提取参数:

from typing import Generic, Tuple, TypeVarTuple, get_args

T = TypeVarTuple("T")

class Base(Generic[*T]):
    values: Tuple[*T]

class Example2(Base[int, str]):
    pass

# 获取原始泛型基类
original_base = Example2.__orig_bases__[0]
# 提取类型参数
type_args = get_args(original_base)
print(type_args)  # 输出:(<class 'int'>, <class 'str'>)

获取values的具体类型

如果需要得到values属性的实际预期类型,可以用提取到的参数构造对应的Tuple类型:

values_type = Tuple[*type_args]
print(values_type)  # 输出:Tuple[int, str]

鲁棒性优化(处理多层继承)

如果存在多层继承,或者不确定基类的位置,可以遍历类的方法解析顺序(MRO)来查找目标泛型基类:

import inspect
from typing import Generic, Tuple, TypeVarTuple, get_args

T = TypeVarTuple("T")

class Base(Generic[*T]):
    values: Tuple[*T]

class Intermediate(Base[int, str]):
    pass

class Example2(Intermediate):
    pass

def get_bound_generic_args(cls, target_base):
    """从子类中提取目标泛型基类的绑定参数"""
    for base in inspect.getmro(cls):
        # 检查当前基类是否是目标泛型的实例
        if getattr(base, '__origin__', None) is target_base:
            return get_args(base)
        # 检查当前基类的原始基类(处理多层继承)
        if hasattr(base, '__orig_bases__'):
            for orig_base in base.__orig_bases__:
                if getattr(orig_base, '__origin__', None) is target_base:
                    return get_args(orig_base)
    return ()

# 使用示例
args = get_bound_generic_args(Example2, Base)
print(args)  # 输出:(<class 'int'>, <class 'str'>)
values_type = Tuple[*args]
print(values_type)  # 输出:Tuple[int, str]

为什么get_args(Example2)返回空?

get_args仅对泛型类的实例(比如Base[int, str])或标注了泛型的对象生效。而Example2是一个被实例化后的具体类,它不再携带泛型参数的信息,除非通过__orig_bases__保留的原始定义来获取。

内容的提问来源于stack exchange,提问作者yotamN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 21:50:16