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

如何从泛型列表中提取泛型实参的联合类型?

解决泛型列表的类型兼容问题与联合类型推断

一、修复MyPy报错的核心方案

你遇到的报错是因为默认的TypeVar是不变的,A[int]和A[int | str]被视为完全不兼容的类型。要解决这个问题,只需将泛型参数定义为协变的:

from typing import Generic, TypeVar

# 定义协变的TypeVar,允许从更具体的泛型实例转换到更宽泛的
T = TypeVar("T", covariant=True)

class A(Generic[T]):
    t: T
    def __init__(self, t: T):
        self.t = t

class B(Generic[T]):
    def foo(self, x: list[A[T]]) -> A[T]:
        return x[0]

a1 = A[int](3)
a2 = A[str]('3')
# 此时MyPy不再报错,因为协变特性允许A[int]赋值给A[int | str]
b = B[int | str]().foo([a1, a2])

协变的含义是:如果X是Y的子类型,那么A[X]也是A[Y]的子类型。这里int和str都是int | str的子类型,所以对应的A实例可以放入list[A[int | str]]中。

二、实现「列表泛型实参的联合类型推断」

针对你最初的Foo类需求,需要将Foo定义为泛型类,结合协变泛型参数,让类型检查器自动推断列表中所有泛型实参的联合类型:

from typing import Generic, TypeVar, List

# 同样用协变TypeVar保证兼容性
T = TypeVar("T", covariant=True)

class MyType(Generic[T]):
    value: T
    def __init__(self, value: T):
        self.value = value

class Foo(Generic[T]):
    def __init__(self, vals: List[MyType[T]]):
        self.vals = vals

# 使用示例:传入不同泛型参数的MyType实例
foo = Foo([MyType[int](1), MyType[str]("hello"), MyType[bool](True)])
# MyPy会自动推断foo的类型为 Foo[int | str | bool]

进阶:捕获可变数量的泛型参数(Python 3.11+)

如果你需要更精确地捕获每个元素的泛型参数(而非直接合并为联合类型),可以使用Python 3.11新增的TypeVarTuple和Unpack特性:

from typing import Generic, TypeVar, TypeVarTuple, Unpack

Ts = TypeVarTuple("Ts")
T = TypeVar("T")

class MyType(Generic[T]):
    value: T
    def __init__(self, value: T):
        self.value = value

class Foo(Generic[Unpack[Ts]]):
    def __init__(self, vals: list[MyType[Unpack[Ts]]]):
        self.vals = vals

# 此时foo的类型为 Foo[int, str, bool],可通过Union[Unpack[Ts]]获取联合类型
foo = Foo([MyType[int](1), MyType[str]("hello"), MyType[bool](True)])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:21:14