Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should one inherit from ABC?

Tags:

python

abc

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?

like image 839
Martin Thoma Avatar asked May 06 '19 16:05

Martin Thoma


People also ask

What is the difference between ABC and ABCMeta?

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.

What is ABC Abstractmethod?

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.

What does abc mean in Python?

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.)

Can a class inherit from multiple abstract classes Python?

You can implement multiple interfaces, but you can't inherit the implementation of multiple classes.


1 Answers

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__ = ()
like image 118
chepner Avatar answered Oct 17 '22 01:10

chepner