I am trying to write an abstract class using Python 3 as shown below:
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")
When I run the file the interpreter does not complain that text.setter is not implemented. Why is there no error?
Both the getter and setter for the text property in your Base class are named text, so they only appear once in the __abstractmethods__ set. When you override the getter in the SubClass, it "counts" as if it had overridden the setter too.
Unfortunately, while a getter-only abstract property works fine, there doesn't really seem to be an elegant way to have a property with both an abstract getter and setter. If you use a single name, then only that name needs to be overridden (and the override need not have a setter, as you've discovered). If you use separate names for those functions and then use text = property(_text_get, _text_set), the concrete subclass will need to replace all three things (the getter, setter and the property object itself). A better approach may be to have the property itself be concrete in the Base class, but have it make calls to abstract getter and setter implementation functions, which can be abstract, and which subclasses can easily override:
@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)
Edit: After reading the docs today for the (now deprecated) abc.abstractproperty, I think I understand a bit better why there's no error from the read-only property (it's not quite as simple as I made it sound above).
The reason you don't get an error is that your new property has a different implementation of "setting" than the base class. That behavior is to raise an exception, of course, but that is technically a different behavior that overrides the behavior of original setter.
If you had updated the old property by using @Base.text.getter as the decorator for the overridden setter function in SubClass rather than creating a new property completely from scratch, you'd get an error about an abstract method text not being overridden.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With