Python只使用修饰符重写abstractmethod属性setter和getter

2024-04-23 21:26:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图创建一个抽象类,它将强制实现同时实现getter和setter。我遵循https://docs.python.org/3.4/library/abc.html#abc.abstractproperty中描述的内容,但是我一直得到

Traceback (most recent call last):
  File "test.py", line 30, in <module>
    test = B('bar')
TypeError: Can't instantiate abstract class B with abstract methods foo

尽管我在B中实现了foogetter和setter

这是我的代码:

^{pr2}$

我知道有一种方法可以在不使用decorator的情况下定义属性,就像这样

from abc import ABC, abstractmethod

class A(ABC):
    @abstractmethod
    def _get_foo(self):
        pass

    @abstractmethod
    def _set_foo(self, val):
        pass

    def do_stuff(self):
        print(self.foo)

    foo = property(_get_foo, _set_foo)

class B(A):
    def __init__(self, val):
        self._foo = val

    def _get_foo(self):
        return self._foo

    def _set_foo(self, val):
        self._foo = val

    foo = property(_get_foo, _set_foo)

if __name__ == '__main__':
    test = B('bar')
    test.do_stuff()
    test.foo = 'barr'
    test.do_stuff()

虽然这确实有效,但肯定有办法让装修工来做,不是吗?在

我运行的是python3.4。在


Tags: testselfabstractgetfoodefbarval
2条回答

根据这个issue,您需要检查层次结构中一个单独实现getter的附加类。然后setter将继续使用具体类:

from abc import ABC, abstractmethod

class A(ABC):

    @property
    @abstractmethod
    def foo(self):
        pass

    @foo.setter
    @abstractmethod
    def foo(self, val):
        pass

    def do_stuff(self):
        print(self.foo)

class B(A):

    _foo = None

    @A.foo.getter
    def foo(self):
        return self._foo

class C(B):

    def __init__(self, val):
        self._foo = val

    @B.foo.setter
    def foo(self, val):
        self._foo = val

if __name__ == '__main__':
    test = C('bar')
    test.do_stuff()
    test.foo = 'barr'
    test.do_stuff()

如果删除B中的getter或C中的setter,将得到所需的TypeError异常。在

然而,这种解决方案迫使您将getter和setter的定义放在两个不同的类中,这在实际应用程序中可能是不切实际的。在

您的代码引发了一个异常,因为您在B.foo方法上使用了A.foo.setter修饰符,因此B.foo方法并没有实际实现具有相同签名的抽象方法A.foo。在

从decorator中删除A.规范,您的代码就可以工作了:

@foo.setter
def foo(self, val):
    self._foo = val

通过修复,您将发现类A确实强制子类实现foo的getter和setter(您看到的异常实际上是由于您没有实现setter)。在

相关问题 更多 >