Abstract Classes Without Abstract Methods Creating Objects In Python
Solution 1:
From the docs:
A class that has a metaclass derived from
ABCMeta
cannot be instantiated unless all of its abstract methods and properties are overridden.
Conversely, this means that any class with no abstract methods or properties like your AbstractClass
can be instantiated.
If you want to disallow instantiation of the topmost parent class, you can write a custom class that performs a type check in its __new__
method:
classSubclassOnlyABC(object):
__metaclass__ = abc.ABCMeta
def__new__(cls, *args, **kwargs):
if cls.__bases__ == (SubclassOnlyABC,):
msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
raise TypeError(msg)
returnsuper(SubclassOnlyABC, cls).__new__(cls, *args, **kwargs)
classAbstractClass(SubclassOnlyABC):
passclassChildClass(AbstractClass):
pass
ChildClass() # works because it's a child class of an abstract class
AbstractClass() # throws TypeError because its parent class is "object"
You can also write a __new__
method that prevents instantiation of classes with no abstract methods:
classNonEmptyABC(object):
__metaclass__ = abc.ABCMeta
def__new__(cls, *args, **kwargs):
# check if ANY abstractmethod existsfor parentcls in cls.__mro__:
ifany(getattr(attr, '__isabstractmethod__', False)
for attr invars(parentcls).values()):
breakelse:
msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
raise TypeError(msg)
returnsuper(NonEmptyABC, cls).__new__(cls, *args, **kwargs)
classEmptyAbstractClass(NonEmptyABC):
passclassNonemptyAbstractClass(NonEmptyABC):
@abc.abstractmethoddeffoo(self):
passclassNonemptyChild(NonemptyAbstractClass):
deffoo(self):
pass
NonemptyChild() # works because "foo" is an abstractmethod
EmptyAbstractClass() # throws TypeError because there are no abstractmethods
Solution 2:
Since Python is a dynamic languages, the very idea of enforcing classes to inherit from a particular class goes against duck typing. Hence, the use case of Abstract classes in Python is pretty limited and provided more for a conventional reason. Still if you want to block the instantiation of a class without declaring virtual methods, you can, however,
classAbstractClass(object):
__metaclass__ = abc.ABCMeta
def__new__(cls, *args, **kwargs):
if cls is AbstractClass:
raise Exception('Abstract class cannot be instantiatied')
returnobject.__new__(*args, **kwargs)
Solution 3:
I usually just declare the base class's __init__
with @abc.abstractmethod
.
If my base class does not have an __init__
, I add a trivial one.
Something like this:
classAbstractClass(abc.ABC):
@abc.abstractmethoddef__init__(self):
pass# other useful non-abstract methods...classChildClass(AbstractClass):
def__init__(self):
passif __name__ == '__main__':
child = ChildClass() # allowed
abstract = AbstractClass() # TypeError
Solution 4:
Here is solution without using ABC. More on specific case it required for here
classAbstractClass:
_is_abstract = Truedef__init__(self):
if self._is_abstract:
raise RuntimeError("Abstract class instantiation.")
# do initializationdef__init_subclass__(self): # is called every time class is subclassed
self._is_abstract = False# thus makes sure abstract check returns False on subclass
Post a Comment for "Abstract Classes Without Abstract Methods Creating Objects In Python"