Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the following code not throw an error?

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?

like image 712
vad Avatar asked Aug 23 '26 05:08

vad


1 Answers

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.

like image 83
Blckknght Avatar answered Aug 25 '26 19:08

Blckknght



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!