Reputation: 1514
In Python, I have an abstract base class which has four methods, of which at least one has to be overwritten. Is it possible to somehow implement this with the @abstractmethod
decorator or something similar?
Here is a stripped down version of the base class:
from abc import ABCMeta
class Base(metaclass=ABCMeta):
def __init__(self, var):
self.var = var
def a(self, r):
return self.var - self.b(r)
def b(self, r):
return self.var * self.c(r)
def c(self, r):
return 1. - self.d(r)
def d(self, r):
return self.a(r) / self.var
The four methods have some kind of cyclic dependency and a subclass has to override at least one of these methods. The rest of the methods then work from the base class.
It might seem a bit strange, but it makes perfectly sense in the application I'm working on.
Upvotes: 2
Views: 954
Reputation: 1514
Thanks to the hint from @NChauhan, I came up with following solution and thanks to a second hint from @NChauhan and from @greeeeeeen, the solution gets a bit shorter and more readable:
from abc import ABCMeta
class Base(metaclass=ABCMeta):
def __init__(self, var):
self.var = var
def __init_subclass__(cls):
super().__init_subclass__()
def a(self, r):
return self.var - self.b(r)
def b(self, r):
return self.var * self.c(r)
def c(self, r):
return 1. - self.d(r)
def d(self, r):
return self.a(r) / self.var
if not hasattr(cls, 'a'):
cls.a = a
if not hasattr(cls, 'b'):
cls.b = b
if not hasattr(cls, 'c'):
cls.c = c
if not hasattr(cls, 'd'):
cls.d = d
if not any(hasattr(cls, method) for method in ('a', 'b', 'c', 'd')):
raise TypeError(f"Can't instantiate class '{cls.__name__}', " +
"without overriding at least on of the methods " +
"'a', 'b', 'c', or 'd'.")
If I would not assign the four methods in the __init_subclass__
method, hasattr
would return True
, because the methods would get inherited.
Upvotes: 3