我正在尝试创建一个抽象类,该类将强制实现同时实现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中同时实现了foo
的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):
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()
我知道有一种方法可以通过定义属性而不使用装饰器来做到这一点,
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()
这确实可行,但肯定有一种方法可以只用装饰器来做到这一点,不是吗?
我正在运行python 3.4。
答案 0 :(得分:0)
您的代码引发异常,因为您在A.foo.setter
方法上使用了B.foo
装饰器,因此B.foo
方法实际上并没有实现抽象方法A.foo
与相同的签名。
从装饰器中删除A.
规范,您的代码将起作用:
@foo.setter
def foo(self, val):
self._foo = val
使用此修复程序,您会发现类A
确实强制子类实现foo
的getter和setter方法(您看到的异常实际上是由于您没有实施设置程序)。
答案 1 :(得分:0)
根据此issue,您需要遍历层次结构中仅实现getter的其他类。然后,设置员将继续使用具体的课程:
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的定义放在两个不同的类中,这在实际应用中可能是不切实际的。