Skip to content Skip to sidebar Skip to footer

Abstract Classes Without Abstract Methods Creating Objects In Python

Basically, I knew that abstract base classes are used as skeleton classes just like regular classes, but enforces that abstract methods should be overridden by the child/inherited

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 AbstractClasscan 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"