Is it a good practice to have non-abstract methods on abstract base classes? I mean, methods that can, but don't have to, be present on subclasses of particular ABC?
Technically it is possible, as seen in the below example (ConcreteDataProvider
does not implement disconnect
; it only has to implement connect
):
from abc import ABC, abstractmethod
class AbstractDataProvider(ABC):
@abstractmethod
def connect(self):
pass
def disconnect(self):
pass
class ConcreteDataProvider(AbstractDataProvider):
def connect(self):
pass
data_provider = ConcreteDataProvider()
It is fine to have ABC with concrete methods to provide default implementations. The standard library has several such cases:
The example of using abc.ABCMeta provides a non-abstract method.
The
get_iterator()
method is also part of the MyIterable abstract base class, but it does not have to be overridden in non-abstract derived classes.
The ABCs of the collections.abc module provide default methods (termed "Mixin Methods").
ABC | Inherits from | Abstract Methods | Mixin Methods |
---|---|---|---|
... | ... | ... | ... |
Iterator | Iterable | __next__ |
__iter__ |
Generator | Iterator | send , throw |
close , __iter__ , __next__ |
... | ... | ... | ... |
When "do nothing" is a sensible default, there is no problem with a concrete method having a default implementation that is just pass
. This can especially be useful when you expect that many implementations will need this method: by providing a default, it is safe for client code to always call this method.
Note: When the pattern is specifically connect/disconnect, open/close, or similar pairs of methods to be called before/after usage, the __enter__
/__exit__
pair of a context manager is the appropriate interface.