如何让typing/mypy识别通过__extends__定义的动态超类继承关系
解决方案
共有4种可落地的方案,均不会破坏现有运行时的类合并逻辑:
方案1:类内self类型绑定
如果仅需要在B类的内部代码中正常访问A的属性,不需要全局识别子类型关系,可直接给B的self加类型绑定:
from typing import TypeVar # 绑定到A类型 AT = TypeVar('AT', bound='A') class B(Pluggable): __extends__ = A # 仅类型检查阶段生效,告知mypy self同时属于A类型 self: AT def demo_method(self): # 这里访问A的属性不会报错 print(self.a_attr)
方案2:TYPE_CHECKING 条件继承
改造成本最低的全局兼容方案,仅在类型检查阶段声明继承关系,运行时完全无感知:
from typing import TYPE_CHECKING if TYPE_CHECKING: # 类型检查阶段显式继承A _Parent = A else: # 运行时保持原继承逻辑,不影响类合并、MRO生成 _Parent = Pluggable class B(_Parent): __extends__ = A
方案3:ABC虚拟子类注册
如果需要全局声明子类型关系,可通过ABC的注册机制实现,运行时不会改变真实继承链:
from abc import ABC # 仅需要让A继承ABC即可,无需修改其他逻辑 class A(Pluggable, ABC): ... class B(Pluggable): __extends__ = A # 注册虚拟继承,mypy会识别该关系,运行时无实际继承行为 A.register(B)
方案4:自定义mypy插件自动识别
如果项目中这类__extends__声明的类很多,可写一个极简mypy插件自动批量处理:
- 编写插件代码:
from mypy.nodes import TypeInfo from mypy.plugin import Plugin, ClassDefContext class ExtendsAttrPlugin(Plugin): def analyze_class(self, ctx: ClassDefContext) -> None: cls_info: TypeInfo = ctx.cls.info extends_entry = cls_info.names.get('__extends__') if not extends_entry or not extends_entry.type: return parent_type_info = extends_entry.type.type # 自动给当前类添加父类型关系 cls_info.mro.insert(1, parent_type_info) cls_info.bases.append(extends_entry.type) def plugin(version: str): return ExtendsAttrPlugin
- 在mypy配置文件(
mypy.ini/pyproject.toml)中添加插件加载配置:
[mypy] plugins = path/to/your/extends_attr_plugin.py
该方案无需修改任何业务代码,即可让mypy自动识别所有__extends__声明的继承关系。
内容的提问来源于stack exchange,提问作者Masklinn
相关产品推荐
相关产品推荐

