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

Python 3.13带类型参数的泛型类继承的类型提示问题

问题根源

你遇到的错误是因为Callable是Python的抽象基类(ABC),运行时它的元类会严格校验继承规则——不允许直接以Callable[[T], bool]这种带类型参数的形式作为父类定义子类,哪怕是泛型类也不行。


解决方案一:用Protocol实现严格类型约束(推荐)

typing.Protocol是专门用于定义结构类型的工具,适合描述可调用对象的接口,支持泛型,且运行时不会触发ABC的严格校验,完全满足你对严格类型提示的需求。

修改后的代码:

from typing import Protocol, TypeVar

T = TypeVar('T')

class Predicate(Protocol[T]):
    """
    Base class for predicates: a function that takes a 'T' and evaluates to True or False.
    """
    def __call__(self, item: T) -> bool: ...

class StartsWith(Predicate[str]):
    def __init__(self, prefix: str):
        self.prefix = prefix

    def __call__(self, s: str) -> bool:
        return s.startswith(self.prefix)

class GreaterThan(Predicate[float]):
    def __init__(self, y: float):
        self.y = y

    def __call__(self, x: float) -> bool:
        return x > self.y

class Not(Predicate[T]):
    def __init__(self, p: Predicate[T]):
        self.p = p

    def __call__(self, item: T) -> bool:
        return not self.p(item)

if __name__ == '__main__':
    assert StartsWith("F")("Foo")
    assert GreaterThan(10)(42)
    assert Not(StartsWith("A"))("Foo")
    assert Not(GreaterThan(10))(3)

此方案中,Protocol定义了Predicate的核心接口,子类实现后,类型检查器(如mypy、pyright)会严格校验泛型类型,同时运行时无报错。


解决方案二:调整Callable继承方式(兼容原有写法)

如果要保留继承Callable的思路,只需改为继承无参数的Callable基类,同时在__call__方法中明确类型提示:

from typing import Callable, TypeVar

T = TypeVar('T')

class Predicate[T](Callable):
    """
    Base class for predicates: a function that takes a 'T' and evaluates to True or False.
    """
    def __init__(self, _eval: Callable[[T], bool]):
        self.eval = _eval

    def __call__(self, item: T) -> bool:
        return self.eval(item)

class StartsWith(Predicate[str]):
    def __init__(self, prefix: str):
        super().__init__(lambda s: s.startswith(prefix))

class GreaterThan(Predicate[float]):
    def __init__(self, y: float):
        super().__init__(lambda x: x > y)

class Not[T](Predicate[T]):
    def __init__(self, p: Predicate[T]):
        super().__init__(lambda x: not p(x))

if __name__ == '__main__':
    assert StartsWith("F")("Foo")
    assert GreaterThan(10)(42)
    assert Not(StartsWith("A"))("Foo")
    assert Not(GreaterThan(10))(3)

此方案避开了ABC的运行时校验,同时类型检查器依然能识别泛型约束,适配你原有的类结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:26:13