from abc import ABC, abstractmethod
class AbstractExample(ABC):
@property
@abstractmethod
def some_prop(self):
pass
class ConcreteExample(AbstractExample):
def some_prop(self):
return None
c = ConcreteExample() # this does not raise
Why should it raise? You have done exactly what an abstract method is for - you implemented some_prop in in a child class.
When some_prop is searched for in a ConcreteExample instance, it will look in the instance, after that in the class, where it finds a usable entry. Because it is not decorated as a property, it is a normal method.
I understand why it does not raise, but it doesn’t make sense. The documentation for abstractproperty hints that this what was intended. I emphasis: ‘…as the property decorator is now correctly identified as abstract when applied to an abstract method’
Yet the example given in that doc suffers from the same issue. Simply copy-paste the last two codeblocks, but remove ‘@C.x.setter’ line in the latter, D still instantiates fine.
from abc import abstractmethod, ABC
class C(ABC):
@property
def x(self): ...
@x.setter
@abstractmethod
def x(self, val): ...
class D(C):
def x(self, val): ...
d = D()
By deleting the decorator you changed the property setter in D to an ordinary method, shadowing the property x. From D the property is no longer reachable. So the quoted part of the answer applies when you change some_prop to x and ConcreteExample to D.