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
相关产品推荐
相关产品推荐

