I always thought one should inherit from abc.ABC
when one does not want the class to be instantiated. But I've just realized that if a class has an @abstractmethod
then one can also not instanciate it.
Is there any other reason to inherit from ABC
?
ABCMeta . i.e abc. ABC implicitly defines the metaclass for us. The only difference is that in the former case you need a simple inheritance and in the latter you need to specify the metaclass.
abc. abstractmethod(function) A decorator indicating abstract methods. Using this decorator requires that the class's metaclass is ABCMeta or is derived from it. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.
Source code: Lib/abc.py. This module provides the infrastructure for defining abstract base classes (ABCs) in Python, as outlined in PEP 3119; see the PEP for why this was added to Python. (See also PEP 3141 and the numbers module regarding a type hierarchy for numbers based on ABCs.)
You can implement multiple interfaces, but you can't inherit the implementation of multiple classes.
Unless you use abc.ABCMeta
as the metaclass for your class (either explicitly or by inheriting from abc.ABC
), using abstractmethod
doesn't really do anything.
>>> from abc import abstractmethod, ABC
>>> class Foo:
... @abstractmethod
... def bar(self):
... pass
...
>>> f = Foo()
>>>
Likewise, using ABCMeta
doesn't mean much unless you mark at least one method as abstract:
>>> class Bar(ABC):
... pass
...
>>> b = Bar()
>>>
It's the combination of the two that allows a class to be (nominally) uninstantiable:
>>> class Baz(ABC):
... @abstractmethod
... def m(self):
... pass
...
>>> b = Baz()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Baz with abstract methods m
>>>
(Even then, note that all @abstractmethod
does is add the decorated method to a set which the metaclass machinery consults when trying to instantiate the class. It is trivial to defeat that machinery:
>>> Baz.__abstractmethods__
frozenset({'m'})
>>> Baz.__abstractmethods__ = set()
>>> b = Baz()
>>>
)
Note that ABC
itself is a trivial class that uses ABCMeta
as its metaclass, which makes any of its descendants use it as well.
# Docstring omitted; see
# https://github.com/python/cpython/blob/3.7/Lib/abc.py#L166
# for the original
class ABC(metaclass=ABCMeta):
__slots__ = ()
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