3

我正在尝试使用 Python 3 编写一个抽象类,如下所示:

from abc import *


class Base(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self, text=''):
        self._text = text

    @property
    @abstractmethod
    def text(self):
        return self._text

    @text.setter
    @abstractmethod
    def text(self, text):
        self._text = text


class SubClass(Base):

    def __init__(self, text):
        super().__init__(text)

    @property
    def text(self):
        return super().text

q = SubClass("Test")

当我运行文件时,解释器不会抱怨 text.setter 没有实现。为什么没有错误?

4

1 回答 1

3

text类中属性的 getter 和 setterBase都命名为text,因此它们只在__abstractmethods__集合中出现一次。当您在 中覆盖 getter 时SubClass,它“计数”就好像它也覆盖了 setter。

不幸的是,虽然只有 getter 的抽象property可以正常工作,但似乎并没有一种优雅的方式来拥有一个同时具有抽象 getter 和 setter 的属性。如果您使用单个名称,则只需要覆盖该名称(并且正如您所发现的那样,覆盖不需要设置器)。如果您对这些函数使用单独的名称然后使用text = property(_text_get, _text_set),则具体的子类将需要替换所有三件事(getter、setter 和属性对象本身)。更好的方法可能是让属性本身在Base类中具体化,但让它调用抽象的 getter 和 setter 实现函数,它们可以是抽象的,并且可以轻松地覆盖哪些子类:

@abstractmethod
def _text_get_imp(self):
    return self._text

@abstractmethod
    _text_set_imp(self, value):
    self._text = value

@property
def text(self):
    return self._text_get_imp()

@text.setter
def text(self, value)
    self._text_set_imp(value)

编辑:今天阅读了(现已弃用)的文档后abc.abstractproperty,我想我更好地理解了为什么只读属性没有错误(它不像我上面所说的那么简单)。

您没有收到错误的原因是您的新属性具有与基类不同的“设置”实现。当然,这种行为是引发异常,但从技术上讲,这是一种不同的行为,它覆盖了原始 setter 的行为。

如果您通过将旧属性@Base.text.getter用作被覆盖的 setter 函数的装饰器而不是完全从头开始SubClass创建新属性来更新旧属性,则会收到关于未覆盖抽象方法的错误。propertytext

于 2014-05-02T19:34:04.547 回答