I found multiple (slightly different) ways to define abstract classes in Python. I read the documentation and also could not find an answer here on stackoverflow.
The main difference between the three examples (see code below) is:
A
sets a new metaclass abc.ABCMeta
explicitlyB
inherits from abc.ABC
C
inherits from objects
but defines @abc.abstractmethod
classesIt seems that A
and B
are not different (i.e. also B
has the new metaclass abc.ABCMeta
). However, class C
remains of type type
.
What are the impacts of not defining a metaclass for C
? When is it necessary to define the metaclass or is it wrong/bad style to not define the abc.ABCMeta
metaclass for an abstract class? Nonetheless, the class C
seems to behave as I expect from an ABC.
import abc
class A(metaclass=abc.ABCMeta):
# Alternatively put __metaclass__ = abc.ABCMeta here
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class B(abc.ABC):
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class C(object):
@abc.abstractmethod
def foo(self):
raise NotImplementedError
class Aimpl(A):
def foo(self):
print("Aimpl")
class Bimpl(B):
def foo(self):
print("Bimpl")
class Cimpl(C):
#def foo(self):
# print("Cimpl")
pass
Aimpl().foo() # Aimpl
print(isinstance(Aimpl, A)) # False
print(issubclass(Aimpl, A)) # True
print(isinstance(Aimpl, abc.ABCMeta)) # True
print(type(A)) # <class 'abc.ABCMeta'>
print("---")
Bimpl().foo() # Bimpl
print(isinstance(Bimpl, B)) # False
print(issubclass(Bimpl, B)) # True
print(isinstance(Bimpl, abc.ABCMeta)) # True
print(type(B)) # <class 'abc.ABCMeta'>
print("---")
Cimpl().foo() # Cimpl
print(isinstance(Cimpl, C)) # False
print(issubclass(Cimpl, C)) # True
print(isinstance(Cimpl, abc.ABCMeta)) # False
print(type(C)) # <class 'type'>
print("---")
Abstract class: is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class). Abstract method: can only be used in an abstract class, and it does not have a body. The body is provided by the subclass (inherited from).
An abstract class is a class that is declared abstract —it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed. When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class.
An abstract class cannot be directly instantiated using the new keyword. A concrete class can be directly instantiated using the new keyword. An abstract class may or may not contain abstract methods. A concrete class cannot contain an abstract method.
The abc.ABCMeta
class is necessary to actually enforce the abstractmethod
behaviour. Its itention is to disallow instantiation of any classes which do not implement the abstract method. The decorator itself cannot enforce that, the metaclass is enforcing the decorator upon instantiation:
class Foo:
@abstractmethod
def bar(self):
pass
Foo() # works
However:
class Foo(metaclass=ABCMeta):
@abstractmethod
def bar(self):
pass
Foo()
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods bar
So, without the metaclass, the abstractmethod
decorator doesn't do anything.
abc.ABC
is merely a shorthand so you can do Foo(ABC)
instead of Foo(metaclass=ABCMeta)
, that is all:
A helper class that has
ABCMeta
as its metaclass. With this class, an abstract base class can be created by simply deriving fromABC
avoiding sometimes confusing metaclass usage [..]https://docs.python.org/3/library/abc.html#abc.ABC
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