如何为抽象方法属性添加类型提示,消除mypy检查报错?
抽象类属性相关的mypy报错解决
问题场景
有两组看似逻辑等效的代码,其中一组能通过mypy检查,另一组却触发报错:
无报错的代码示例
from abc import ABC, abstractmethod class TableLoader(ABC): @property @abstractmethod def FieldToDataHeaderKey(self): # dict of model dicts of field names and header keys pass def set_headers(self, custom_headers=None): for mdl in self.FieldToDataHeaderKey.keys(): pass class StudyTableLoader(TableLoader): FieldToDataHeaderKey = { Study.__name__: { "code": CODE_KEY, "name": NAME_KEY, "description": DESC_KEY, }, }
触发报错的代码示例
from abc import ABC, abstractmethod class PeakAnnotationsLoader(ABC): @property @abstractmethod def add_columns_dict(self): pass @classmethod def add_df_columns(cls, df_dict: dict): for sheet, column_dict in cls.add_columns_dict.items(): # ^^^ 此行触发mypy报错 ... class IsocorrLoader(PeakAnnotationsLoader): add_columns_dict = {}
mypy报错信息
DataRepo/loaders/peak_annotations_loader.py:213: error: "Callable[[PeakAnnotationsLoader], Any]" has no attribute "items" [attr-defined] DataRepo/loaders/peak_annotations_loader.py:321: error: Need type annotation for "add_columns_dict" (hint: "add_columns_dict: Dict[<type>, <type>] = ...") [var-annotated]
报错原因
- 访问方式不匹配:第一个示例中
set_headers是实例方法,通过self.FieldToDataHeaderKey访问属性——子类的FieldToDataHeaderKey是类属性,Python允许实例访问类属性,mypy能正确推断其为字典类型,因此调用.keys()无问题。而第二个示例中add_df_columns是类方法,通过cls.add_columns_dict访问时,抽象类中定义的add_columns_dict是实例属性的getter方法(@property修饰的抽象方法),mypy会将cls.add_columns_dict识别为可调用对象(而非字典),因此报错“无items属性”。 - 缺少类型注解:子类
IsocorrLoader中的add_columns_dict未添加类型注解,触发mypy的var-annotated检查。
解决方法
方案1:将类方法改为实例方法(对齐第一个示例的逻辑)
如果业务逻辑允许,把add_df_columns改为实例方法,通过self访问属性,同时给抽象属性和子类属性添加明确的类型注解:
from abc import ABC, abstractmethod from typing import Dict, Any class PeakAnnotationsLoader(ABC): @property @abstractmethod def add_columns_dict(self) -> Dict[Any, Any]: pass # 改为实例方法 def add_df_columns(self, df_dict: dict): for sheet, column_dict in self.add_columns_dict.items(): ... class IsocorrLoader(PeakAnnotationsLoader): # 添加类型注解,根据实际业务调整具体类型 add_columns_dict: Dict[Any, Any] = {}
方案2:定义类级别的抽象属性(适配类方法场景)
如果必须保留类方法,需要将add_columns_dict定义为类级别的抽象属性,使用ClassVar标注类型,确保mypy识别其为类属性而非实例属性的getter:
from abc import ABC from typing import Dict, Any, ClassVar class PeakAnnotationsLoader(ABC): # 声明类级别的抽象属性类型 add_columns_dict: ClassVar[Dict[Any, Any]] @classmethod def add_df_columns(cls, df_dict: dict): for sheet, column_dict in cls.add_columns_dict.items(): ... class IsocorrLoader(PeakAnnotationsLoader): # 实现类属性并添加类型注解 add_columns_dict: ClassVar[Dict[Any, Any]] = {}
若需要强制子类必须实现该属性,可以在抽象类中添加__init_subclass__进行校验:
from abc import ABC from typing import Dict, Any, ClassVar class PeakAnnotationsLoader(ABC): add_columns_dict: ClassVar[Dict[Any, Any]] def __init_subclass__(cls) -> None: super().__init_subclass__() if not hasattr(cls, 'add_columns_dict'): raise NotImplementedError("所有子类必须定义add_columns_dict类属性") @classmethod def add_df_columns(cls, df_dict: dict): for sheet, column_dict in cls.add_columns_dict.items(): ... class IsocorrLoader(PeakAnnotationsLoader): add_columns_dict: ClassVar[Dict[Any, Any]] = {}
内容的提问来源于stack exchange,提问作者hepcat72
相关产品推荐
相关产品推荐

