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

Python/mypy中判断泛型类型子类型关系的简便及交互式方法

Python泛型子类型关系的交互式判断方法

Python内置的issubclass()无法直接判断参数化泛型的子类型关系,因为参数化泛型(如list[bool])不属于合法的issubclass()第二个参数类型,会触发TypeError。我们可以通过解析泛型的原始类、类型参数以及泛型的变异性(协变/逆变/不变)来实现自定义判断逻辑。

基础实现(支持协变场景)

先实现一个基础版本,处理单参数/多参数泛型的子类型判断,默认适配list这类容器的协变行为:

from typing import get_origin, get_args

def is_generic_subclass(sub, sup):
    # 获取泛型的原始类(如list[bool]的原始类是list)
    sub_origin = get_origin(sub)
    sup_origin = get_origin(sup)
    
    # 处理非参数化泛型的常规判断
    if sub_origin is None or sup_origin is None:
        try:
            return issubclass(sub, sup)
        except TypeError:
            return False
    
    # 泛型本身必须是子类关系(如list是Sequence的子类)
    if not issubclass(sub_origin, sup_origin):
        return False
    
    sub_args = get_args(sub)
    sup_args = get_args(sup)
    if len(sub_args) != len(sup_args):
        return False
    
    # 逐个检查类型参数的子类型关系(协变逻辑:子泛型的参数需是父泛型参数的子类)
    for sub_arg, sup_arg in zip(sub_args, sup_args):
        if not issubclass(sub_arg, sup_arg):
            return False
    return True

测试示例:

# 基础容器泛型测试
print(is_generic_subclass(list[bool], list[int]))  # 输出True,因为bool是int的子类
print(is_generic_subclass(list[int], list[bool]))  # 输出False
print(is_generic_subclass(dict[str, int], dict[object, object]))  # 输出True,str、int均为object子类

进阶实现(支持协变/逆变/不变)

如果需要处理自定义泛型的变异性(如逆变的Callable),可以进一步解析泛型类的TypeVar变异性,调整判断逻辑:

from typing import get_origin, get_args, Generic, TypeVar

def is_generic_subclass(sub, sup):
    sub_origin = get_origin(sub)
    sup_origin = get_origin(sup)
    
    if sub_origin is None or sup_origin is None:
        try:
            return issubclass(sub, sup)
        except TypeError:
            return False
    
    if not issubclass(sub_origin, sup_origin):
        return False
    
    sub_args = get_args(sub)
    sup_args = get_args(sup)
    if len(sub_args) != len(sup_args):
        return False
    
    # 获取泛型类定义的TypeVar及其变异性
    type_vars = sub_origin.__parameters__
    for idx, (sub_arg, sup_arg) in enumerate(zip(sub_args, sup_args)):
        tv = type_vars[idx]
        if tv.__covariant__:
            # 协变:子参数需是父参数的子类
            if not issubclass(sub_arg, sup_arg):
                return False
        elif tv.__contravariant__:
            # 逆变:父参数需是子参数的子类(如Callable[[int], None]是Callable[[bool], None]的子类)
            if not issubclass(sup_arg, sub_arg):
                return False
        else:
            # 不变:类型参数必须完全一致
            if sub_arg is not sup_arg:
                return False
    return True

测试逆变场景:

# 定义逆变泛型类
T_contra = TypeVar('T_contra', contravariant=True)
class MyContravariant(Generic[T_contra]):
    pass

# 逆变逻辑下,MyContravariant[int]是MyContravariant[bool]的子类
print(is_generic_subclass(MyContravariant[int], MyContravariant[bool]))  # 输出True
print(is_generic_subclass(MyContravariant[bool], MyContravariant[int]))  # 输出False

你可以直接调用上述is_generic_subclass()函数,交互式地判断任意泛型的子类型关系,无需担心issubclass()的报错问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 12:02:48