Python/mypy:如何声明支持属性或property实现的抽象基类ABC
问题原因
mypy报错的核心原因是:基类中声明的n: int默认可读写,而Y类中仅实现了getter的property是只读属性,二者的可变契约不匹配,因此被判定为签名不兼容。
解决方案
方案1:将基类n声明为抽象只读property(最推荐)
你之前担心的子类X无法通过校验的问题不存在,mypy原生支持使用普通实例属性实现抽象property的契约,只要属性类型匹配即可,改造后代码如下:
from abc import ABC, abstractmethod class Base(ABC): @property @abstractmethod def n(self) -> int: ... def foo(self): # foo方法的类型校验完全正常 a = 1 + self.n @abstractmethod def bar(self): ... class X(Base): def __init__(self, n: int): self.n = n # 实例属性满足只读契约,mypy无报错 def bar(self): ... class Y(Base): @property def n(self) -> int: # 你的业务实现逻辑 return 2 def bar(self): ...
该方案完全符合类型规范,同时明确了n仅读不可写的契约,适合绝大多数场景。
方案2:用ReadOnly标注基类属性
如果你不想使用抽象property,也可以用ReadOnly标记基类的n为只读属性,低版本Python需要先安装typing-extensions导入该类型:
from abc import ABC, abstractmethod from typing import ReadOnly # Python<3.11 请用 from typing_extensions import ReadOnly class Base(ABC): n: ReadOnly[int] def foo(self): a = 1 + self.n @abstractmethod def bar(self): ... # X、Y类不需要做任何改造即可通过mypy校验
方案3:为Y的property补充setter(仅适合允许修改n的场景)
如果业务逻辑允许修改Y实例的n,可以给property增加setter实现,让其可写性和基类声明对齐:
class Y(Base): _n: int = 2 @property def n(self) -> int: return self._n @n.setter def n(self, value: int): self._n = value def bar(self): ...
内容的提问来源于stack exchange,提问作者shaunc
相关产品推荐
相关产品推荐

