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 classes if it has one like below
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
@abstractmethod
def absmethod(self):
pass
class ChildClass(AbstractClass):
def absmethod(self):
print "Yeah!"
obj = ChildClass()
So we can create an object of ChildClass
as above
We know we can't instantiate an abstract class as it meant to be just skeleton and we will get an error if we try to instantiate it as below
obj = AbstractClass()
*** TypeError: Can't instantiate abstract class AbstractClass with abstract methods absmethod
But what my actual query about posting this StackOverflow
is if we create an abstract class by using abc.ABCMeta
, without abstract methods, I can able to create an instance of the abstract class which should not be the case(correct me if I am wrong)
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
obj = AbstractClass()
OOOPPPSS it worked, we can actually create an object of abstract classes without abstract methods? So please let me know the key points behind this
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,
class AbstractClass(object):
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kwargs):
if cls is AbstractClass:
raise Exception('Abstract class cannot be instantiatied')
return object.__new__(*args, **kwargs)
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:
class SubclassOnlyABC(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)
return super(SubclassOnlyABC, cls).__new__(cls, *args, **kwargs)
class AbstractClass(SubclassOnlyABC):
pass
class ChildClass(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:
class NonEmptyABC(object):
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kwargs):
# check if ANY abstractmethod exists
for parentcls in cls.__mro__:
if any(getattr(attr, '__isabstractmethod__', False)
for attr in vars(parentcls).values()):
break
else:
msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
raise TypeError(msg)
return super(NonEmptyABC, cls).__new__(cls, *args, **kwargs)
class EmptyAbstractClass(NonEmptyABC):
pass
class NonemptyAbstractClass(NonEmptyABC):
@abc.abstractmethod
def foo(self):
pass
class NonemptyChild(NonemptyAbstractClass):
def foo(self):
pass
NonemptyChild() # works because "foo" is an abstractmethod
EmptyAbstractClass() # throws TypeError because there are no abstractmethods
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With