此代码:
class PeakAnnotationsLoader(ABC):
@property
@abstractmethod
def add_columns_dict(self) -> Optional[Dict[str, Dict[str, function]]]:
pass
@classmethod
def add_df_columns(cls, df_dict: dict):
if cls.add_columns_dict is not None:
for sheet, column_dict in cls.add_columns_dict.items():
# ^^^ This is the line that produces the error
...
class IsocorrLoader(PeakAnnotationsLoader):
add_columns_dict = None
从
mypy
产生以下错误:
DataRepo/loaders/peak_annotations_loader.py:222: error: "Callable[[PeakAnnotationsLoader], Optional[dict[str, dict[str, function]]]]" has no attribute "items" [attr-defined]
我最初根本没有该方法的类型提示,并且遇到了同样的错误,但我不知道如何让 mypy 在这里开心。顺便说一句,该代码有效。我如何在这里满足我的要求?
在
PeakAnnotationsLoader
类中, add_columns_dict
方法位于实例级别,而 add_df_columns
方法位于类级别。使用 cls.add_columns_dict
就像使用 PeakAnnotationsLoaderChildClass.add_columns_dict
一样,理论上它会返回 mypy 所说的返回值,一个可调用的。
代码之所以有效,是因为您重写了
add_columns_dict
方法并将其设为静态字段,因此 PeakAnnotationsLoaderChildClass.add_columns_dict
返回该字段的值。父类不会以任何方式强制子类覆盖 add_columns_dict
,因此 mypy 会抛出此错误。
如果通过删除
add_columns_dict
注释使 @classmethod
方法成为实例级方法,该错误就会消失。
覆盖抽象属性的预期方法如下:
class IsocorrLoader(PeakAnnotationsLoader):
@property
def add_columns_dict(self) -> Optional[Dict[str, Dict[str, function]]]:
...
这会破坏你的代码,并且它不再起作用,因为你不再将
add_columns_dict
设为类的静态字段。
根据我目前的知识,不可能有一个抽象类方法同时也是一个属性。
使
add_columns_dict
成为抽象类方法而不是抽象属性也可以使此错误消失。您的代码可能如下所示:
class PeakAnnotationsLoader(ABC):
@classmethod
@abstractmethod
def get_add_columns_dict(self) -> Optional[Dict[str, Dict[str, function]]]:
pass
@classmethod
def add_df_columns(cls, df_dict: dict):
add_columns_dict = cls.get_add_columns_dict()
if add_columns_dict is not None:
for sheet, column_dict in add_columns_dict.items():
...
class IsocorrLoader(PeakAnnotationsLoader):
@classmethod
def get_add_columns_dict(self) -> Optional[Dict[str, Dict[str, function]]]:
...