为什么以下代码不会抛出错误?

时间:2014-05-02 19:07:25

标签: python python-3.x properties abstract-methods

我正在尝试使用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没有实现。为什么没有错误?

1 个答案:

答案 0 :(得分:3)

text类中Base属性的getter和setter都被命名为text,因此它们只在__abstractmethods__集中出现一次。当您在SubClass中覆盖getter时,它会计算""好像它也覆盖了二传手。

不幸的是,虽然只有getter的抽象property工作正常,但似乎并不是一个优雅的方法来拥有一个带有抽象getter和setter的属性。如果您使用单个名称,则只需要覆盖该名称(并且覆盖不需要具有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作为SubClass中被覆盖的setter函数的装饰器更新了旧属性,而不是从头开始创建新的property,那么您可以得到一个关于抽象方法text未被覆盖的错误。