I am learning the abc
module and was wondering if what I want to do is possible.
Essentially, every child I make of the base class should have the SAME exact __init__
. The base class will have a few abstract properties that will need to be defined by the child. I would to define those abstract properties without having to rewrite the entire __init__
every time.
Example:
I initially tried something like this
from abc import ABC,abstractmethod
class test(ABC):
def __init__(self):
pass
@property
@abstractmethod
def prop(self):
pass
class prop_ex(test):
@property
def prop(self):
return "THIS WORKS"
>>> from abc_tests import prop_ex
>>> blah = prop_ex()
>>> blah.prop
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'prop_ex' object has no attribute 'prop'
it didn't work.
Then I tried
from abc import ABC,abstractmethod
class test(ABC):
def __init__(self):
self.prop = prop
@property
@abstractmethod
def prop(self):
pass
class prop_ex(test):
prop = "THIS WORKS"
@property
def prop(self):
return self._prop
Test
>>> from abc_tests import prop_ex
>>> blah = prop_ex()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "abc_tests.py", line 13, in __init__
self.prop = prop
NameError: name 'prop' is not defined
No good either, so then I tried
from abc import ABC,abstractmethod
class test(ABC):
def __init__(self):
pass
@property
@abstractmethod
def prop(self):
pass
class prop_ex(test):
self.prop = "THIS WORKS"
@property
def prop(self):
return self._prop
test
>>> from dunder_tests import prop_ex
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "abc_tests.py", line 39, in <module>
class prop_ex(test):
File "abc_tests.py", line 40, in prop_ex
self.prop = "THIS WORKS"
NameError: name 'self' is not defined
For the last one if you set a breakpoint in __init__
of the parent and do a dir(self)
you'll see 'prop'
in it.
>>> blah = prop_ex()
> abc_tests.py(14)__init__()
-> self.prop = prop
(Pdb) dir(self)
['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_impl', 'prop']
So I thought that would work.
Edit:
I see I am completely over complicating this. I could have simply did
from abc import ABC,abstractmethod
class test(ABC):
def __init__(self):
pass
@property
@abstractmethod
def prop(self):
pass
class prop_ex(test):
prop = "THIS WORKS"
Is there an issue with doing it this way?
As you've correctly summized, the most straight-forward solution would be to define an abstractproperty
and simply let the subclass define it, no need for __init__
at all.
I would go a step further and throw an Exception in the base-class just to make sure there's no stray super()
call on it.
import abc
class test(abc.ABC):
@property
@abc.abstractmethod
def prop(self):
raise NotImplementedException()
class prop_ex(test):
prop = "THIS WORKS"
By the way: Your first example already worked for me. The other two don't work because the second approach tries to find a local variable called prop
which doesn't exist and the third approach references self
in the class body - but self
is only defined in methods/properties of a class, not in the class body.
Also this doesn't prevent __init__
from being overridden in subclasses, any subclass may still modify the __init__
.