在抽象基类中定义 @property.setter 会产生 AttributeError

Posted

技术标签:

【中文标题】在抽象基类中定义 @property.setter 会产生 AttributeError【英文标题】:Defining @property.setter in Abstract Base Class gives AttributeError 【发布时间】:2020-03-25 20:40:04 【问题描述】:

一个抽象基类Base 有一个名为data@abstractmethod,它也是一个@property

问题:有没有办法在Base类中定义属性setter data.setter,这样我们就不用在所有子类中重复定义setter方法了(即Foo)?

在 ABC 中定义 data.setter 时显示 AttributeError 的代码

from abc import ABC, abstractmethod

def reload_data():
    return ['hello']


class Base(ABC):
    @property
    @abstractmethod
    def data(self):
        pass

    @data.setter               # <----- AttributeError if this is defined here
    def data(self, value):
        self._data = value


class Foo(Base):
    def __init__(self):
        self._data = None

    @property
    def data(self):
        if self._data is None:
            self._data = reload_data()
        return self._data

    # @data.setter              # <----- Defining it here avoids AttributeError, but 
    # def data(self, value):             causes code repetition in all the subclasses of Base
    #     self._data = value

foo = Foo()
foo.data = ['world']
print(foo.data)

【问题讨论】:

你试过docs.python.org/3/library/abc.html#abc.abstractmethod中的例子吗? @jonrsharpe 抱歉,我尝试阅读链接的文档,但缺乏了解如何将其应用于我的问题的知识。在这里的任何帮助将不胜感激! 不需要太多的知识;它显示了一个正在应用的 setter,您只需要更改名称。 @jonrsharpe:遵循文档中的配方并不能解决问题。 那么请给个minimal reproducible example。 【参考方案1】:

我不知道是否有办法使用 @property 装饰器来完成,但如下所示“手动”执行似乎可行。

from abc import ABC, abstractmethod


def reload_data():
    return ['hello']


class Base(ABC):
    @abstractmethod
    def _get_data(self):
        pass

    # Non-abstract.
    def _set_data(self, value):
        self._data = value


class Foo(Base):
    def __init__(self):
        self._data = None

    # Define inherited abstract method.
    def _get_data(self):
        if self._data is None:
            self._data = reload_data()
        return self._data

    data = property(_get_data, Base._set_data)


foo = Foo()
foo.data = ['world']
print(foo.data)  # ['world']

【讨论】:

以上是关于在抽象基类中定义 @property.setter 会产生 AttributeError的主要内容,如果未能解决你的问题,请参考以下文章

基类中抽象方法的包装器实现

纯虚函数和抽象类

多态—— 纯虚函数和抽象类

抽象类

派生自抽象基类并调用另一个类中的方法的 C++ 包装类,该类也派生自抽象基类

抽象派生类中的抽象方法覆盖/实现抽象基类的抽象或具体方法。如何以及为啥?