简体   繁体   English

Python 仅使用装饰器覆盖抽象方法属性设置器和获取器

[英]Python override abstractmethod property setter and getter using decorators only

I'm trying to create an abstract class that would force the implementation to implement both a getter and a setter.我正在尝试创建一个抽象类,该类将强制实现同时实现 getter 和 setter。 I'm following what is described at https://docs.python.org/3.4/library/abc.html#abc.abstractproperty but I keep getting我正在关注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

even though I implement both foo getter and setter in B.即使我在 B 中实现了foo getter 和 setter。

Here is my code:这是我的代码:

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):
    def __init__(self, val):
        self._foo = val

    @property
    def foo(self):
        return self._foo

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

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

I know there is a way to do this by defining the property without using the decorator, like so我知道有一种方法可以通过定义属性而不使用装饰器来做到这一点,就像这样

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()

While this does work, there surely must be a way to do that with just the decorators, no?虽然这确实有效,但肯定有一种方法可以仅使用装饰器来做到这一点,不是吗?

I'm running python 3.4.我正在运行 python 3.4。

Your code raises an exception because you're using the A.foo.setter decorator on the B.foo method, so the B.foo method does not actually implement the abstract method A.foo with the same signature.您的代码引发异常,因为您在B.foo方法上使用A.foo.setter装饰器,因此B.foo方法实际上并未实现具有相同签名的抽象方法A.foo

Remove the A. specification from the decorator, and your code would work:从装饰器中删除A.规范,您的代码将起作用:

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

With the fix, you'll find that the class A does enforce that the child classes implement both the getter and the setter for foo (the exception you saw was actually a result of you not implementing the setter).通过修复,您会发现A类确实强制子类同时实现foo的 getter 和 setter(您看到的异常实际上是您没有实现 setter 的结果)。

According to this issue you would need to go over an additional class in the hierarchy that implements solely the getter.根据此问题,您需要查看层次结构中仅实现 getter 的附加类。 The setter would then stay with the concrete class:然后 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()

If you remove either the getter in B or the setter in C you will get the desired TypeError exception.如果您删除 B 中的 getter 或 C 中的 setter,您将获得所需的TypeError异常。

This solution, however, forces you to put the definitions of getter and setter in two different classes, which might be impractical in real applications.但是,此解决方案迫使您将 getter 和 setter 的定义放在两个不同的类中,这在实际应用中可能不切实际。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM