使用受限的 TypeVar 继承泛型 类

Inheriting Generic classes with restricted TypeVar

考虑一对简单的泛型 类:

T = TypeVar("T", str, int)

class Base(Generic[T]):
    def __init__(self, v: T):
        self.v: T = v

    @property
    def value(self) -> T:
        return self.v

class Child(Base[T]):
    def __init__(self, v: T):
        super().__init__(v)

x = Child(123)
reveal_type(x.value)

使用 T = TypeVar("T") 时按预期工作。如图所示,受限制的 TypeVar 会产生以下错误:

error: Argument 1 to "__init__" of "Base" has incompatible type "str"; expected "T"
error: Argument 1 to "__init__" of "Base" has incompatible type "int"; expected "T"
note: Revealed type is 'builtins.int*'

请注意 reveal_type 仍然有效。

另一个区别是,受限制的 TypeVar 需要类型注释才能进行 self.v 赋值,而不受限制的则不需要。

在完整的用例中,我实际上有 Callable[[Any], T],但问题是一样的。

这是 mypy 0.910Python 3.9.7

这似乎在您调用 super() 并将通用受限 TypeVar 参数传递给任何函数而不仅仅是 init 时发生。在这些情况下,我相信我们可以通过在这些行中包含 # type: ignore 来要求 mypy 保留这个可怜的东西:

   ...
   super().__init__(v) # type: ignore
   ...

它并没有看起来那么糟糕,因为类型检查仍将在其他行上进行,这与从父函数或子函数的参数中删除 : T 时发生的情况不同 (这些中的任何一个都足以抑制抱怨,但也会停止检查这些函数内部。

T 绑定到 Union[int,str] 应该可以完成工作:

T = TypeVar("T", bound=Union[str, int])


class Base(Generic[T]):

    def __init__(self, v: T):
        self.v: T = v

    @property
    def value(self) -> T:
        return self.v


class Child(Base[T]):

    def __init__(self, v: T):
        super().__init__(v)


x = Child(123)
reveal_type(x.value)
y = Child('a')
reveal_type(y.value)