如何正确在抽象基类中定义可读写的抽象属性

2次阅读

如何正确在抽象基类中定义可读写的抽象属性

本文详解 Python 抽象基类(ABC)中定义带 getter 和 setter 的抽象属性的正确方式,重点解决因装饰器顺序错误导致的 AttributeError: attribute ‘__isabstractmethod__’ of ‘Property’ objects is not writable 问题。

本文详解 python 抽象基类(abc)中定义带 getter 和 setter 的抽象属性的正确方式,重点解决因装饰器顺序错误导致的 `attributeerror: attribute ‘__isabstractmethod__’ of ‘property’ objects is not writable` 问题。

在 Python 的抽象基类(ABC)中,若需声明一个既可读又可写的抽象属性(即同时具备 getter 和 setter),必须严格遵循装饰器的嵌套顺序规则。核心原则是:@abc.abstractmethod 必须作为最内层装饰器(innermost decorator),而 @property 及其 @.setter 则应置于其外层。

这是因为 @abc.abstractmethod 的作用是将方法标记为抽象,并修改其 __isabstractmethod__ 属性;而 property 对象的该属性是只读的。若将 @abc.abstractmethod 写在 @property 外层(如原代码中 @property @abc.abstractmethod),Python 会尝试向 property 实例写入 __isabstractmethod__,从而触发 AttributeError。

✅ 正确写法如下:

import abc  class MyClass(abc.ABC):     @property     @abc.abstractmethod  # ✅ 内层:先抽象,再包装为 property     def current_light(self) -> str:         """当前灯光设置(getter)。"""         ...      @current_light.setter     @abc.abstractmethod  # ✅ 内层:setter 同样需先抽象     def current_light(self, value: str) -> None:         """设置当前灯光(setter)。"""         ...

⚠️ 注意事项:

  • 不要颠倒顺序(如 @abc.abstractmethod @property 或 @abc.abstractmethod @current_light.setter),否则必然报错;
  • 抽象属性的 getter 和 setter 必须分别标注 @abc.abstractmethod,二者缺一不可;
  • 具体子类中实现时,需同时重写 getter 和 setter 方法(且不能遗漏 @property 和 @.setter 装饰器);

例如,一个合法的子类实现:

class ConcreteClass(MyClass):     def __init__(self):         self._light = "off"      @property     def current_light(self) -> str:         return self._light      @current_light.setter     def current_light(self, value: str) -> None:         if value not in ("on", "off", "dim"):             raise ValueError("Invalid light setting")         self._light = value

总结:抽象属性的本质是“抽象的方法对”,而非单一抽象字段。因此,它由两个独立的抽象方法(getter/setter)组成,每个都必须用 @abc.abstractmethod 显式标记,并确保该装饰器处于装饰链最内侧。遵循此规范,即可彻底避免 __isabstractmethod__ 不可写引发的运行时错误。

text=ZqhQzanResources