2

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()
barciewicz
  • 3,511
  • 6
  • 32
  • 72
  • The standard library has many default, non-abstract methods in ``collections.abc``. Now whether that counts as "good practice", well... – MisterMiyagi Feb 17 '22 at 12:40
  • Hi, If the methods can but don't need to be included then in my opinion you should define them in the subclass where you will need them and not in the super class.Good luck – baskettaz Feb 17 '22 at 12:44
  • 1
    @baskettaz: Thanks. The thing is there would be more subclasses that will need the methods (and also subclasses that will not need them at all), and mostly the methods would be implemented the same, so there would be code duplication. That is why I wanted to put the default - but optional - implementations on ABC. – barciewicz Feb 17 '22 at 13:18
  • Now i have better overview what you try to do, in my opinion you can split the needed and optional in two classes and then to inherit from them when you need to ... – baskettaz Feb 17 '22 at 13:46

1 Answers1

4

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.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119