Consider the following sample code:
from abc import ABC, abstractmethod, abstractproperty
class Base(ABC):
@abstractmethod
def foo(self) -> str:
print("abstract")
@property
@abstractmethod
def __name__(self) -> str:
return "abstract"
@abstractmethod
def __str__(self) -> str:
return "abstract"
@property
@abstractmethod
def __add__(self, other) -> str:
return "abstract"
class Sub(Base):
def foo(self):
print("concrete")
def __str__(self):
return "concrete"
def __add__(self, other) -> str:
return "concrete"
sub = Sub()
sub.foo()
sub.__name__
print(str(sub))
Note that the subclass does not implement the abstract property __name__
, and indeed when __name__
is referenced, it prints as "abstract" from its parent:
>>> sub.foo()
concrete
>>> sub.__name__
'abstract'
>>> print(str(sub))
concrete
However, it is not because __name__
is a dunder method, nor because of some issue with @property
and @abstractmethod
decorators not working well together, because if I remove the implementation of __add__
from Sub
, it does not let me instantiate it. (I know __add__
is not normally a property, but I wanted to use a 'real' dunder method) The same expected behavior occurs if I remove the implementation of __str__
and foo
. Only __name__
behaves this way.
What is it about __name__
that causes this behavior? Is there some way around this, or do I need to have the parent (abstract) implementation manually raise the TypeError
for me?