未实例化抽象类时mypy为何抛出‘无法实例化抽象类’错误?
代码运行正常但mypy报错的原因与解决方法
问题根源
这段代码运行正常但触发mypy报错的核心原因是mypy对多元素列表的类型推断逻辑差异:
- 当
CLASSES仅包含2个子类时,mypy会将列表类型推断为具体子类类型的联合集合(例如List[Union[Type[A], Type[B]]]),能明确每个元素都是可实例化的具体类,因此不会报错。 - 当
CLASSES包含3个及以上子类时,mypy会将列表类型泛化为父抽象类的类型集合(List[Type[Abc_]])。此时mypy无法确定列表中的元素是否都是抽象类的合法实现(Type[Abc_]类型理论上包含抽象类Abc_本身),因此抛出“无法实例化抽象类”的错误。
你并未直接实例化Abc_,但mypy的类型推断泛化行为导致了这个误报。
解决方案
以下几种方式可解决该问题:
1. 给CLASSES添加精确的显式类型注解
通过明确标注CLASSES的类型为具体子类类型的联合,让mypy清晰识别每个元素都是可实例化的具体类:
from typing import List, Type, Union from abc import ABC, abstractmethod class Abc_(ABC): def __init__(self) -> None: pass @abstractmethod def f(self) -> str: return "Abc" class A(Abc_): def f(self) -> str: return "a" class B(Abc_): def f(self) -> str: return "b" class C(Abc_): def f(self) -> str: return "c" class DynamicClassInsantiator(object): # 显式标注为三个子类类型的联合列表 CLASSES: List[Union[Type[A], Type[B], Type[C]]] = [A, B, C] @property def stuff(self) -> List[str]: return [cls().f() for cls in self.CLASSES] print(DynamicClassInsantiator().stuff)
2. 使用TypeVar绑定抽象类子类(更具扩展性)
如果后续需要添加更多Abc_的子类,这种方式无需频繁修改类型注解:
from typing import List, Type, TypeVar from abc import ABC, abstractmethod # 定义TypeVar,绑定到Abc_的子类 T = TypeVar('T', bound=Abc_) class Abc_(ABC): def __init__(self) -> None: pass @abstractmethod def f(self) -> str: return "Abc" class A(Abc_): def f(self) -> str: return "a" class B(Abc_): def f(self) -> str: return "b" class C(Abc_): def f(self) -> str: return "c" class DynamicClassInsantiator(object): # 标注为绑定Abc_子类的类型列表 CLASSES: List[Type[T]] = [A, B, C] @property def stuff(self) -> List[str]: return [cls().f() for cls in self.CLASSES] print(DynamicClassInsantiator().stuff)
3. 临时抑制mypy错误(仅应急使用)
若不想修改类型注解,可在实例化代码处添加注释抑制错误:
@property def stuff(self) -> List[str]: return [cls().f() for cls in self.CLASSES] # type: ignore[abstract]
验证
修改后重新执行mypy path/to/file.py,报错会消失,同时代码运行逻辑不受影响。
内容的提问来源于stack exchange,提问作者jamiet
相关产品推荐
相关产品推荐

