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

未实例化抽象类时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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:40:36