13

I would like to know if it is possible to use multiple inheritance with abstract base class in python. It seems like it should be possible but can't find a statement one way or the other.

The basic ABC example:


from abc import ABC, abstractmethod


class BaseABC(ABC):

    @abstractmethod
    def hello(self):
        pass


class Child(BaseABC):
    pass


child = Child()

This will fail due to "hello" not being implemented in "Child".

What I would like is to know how to combine ABC with multiple inheritance. I would like to make either the "BaseABC" or "Child" to inherit also from some other separate class. Explicitly:


from abc import ABC, abstractmethod


class BaseABC(ABC, dict):

    @abstractmethod
    def hello(self):
        pass


class Child(BaseABC):
    pass


child = Child()

This does not fail in the way expected as the first case does. Also:


from abc import ABC, abstractmethod


class BaseABC(ABC):

    @abstractmethod
    def hello(self):
        pass


class Child(BaseABC, dict):
    pass


child = Child()

This does not fail either. How can I require "Child" to implement "hello"?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
kerzane
  • 375
  • 3
  • 8

1 Answers1

6

The issue is with inheriting from a dict, which is probably better explained by these guys:

From my understanding, the built-in list, dict, and set types have in-lined a lot of code for performance. Essentially, they’ve copy-pasted the same code between many different functions to avoid extra function calls and make things a tiny bit faster.

I haven’t found a reference online that explains why this decision was made and what the consequences of the alternatives to this choice were. But I mostly trust that this was done for my benefit as a Python developer. If dict and list weren’t faster this way, why would the core developers have chosen this odd implementation?

It happens, because Python built-in dict is implemented on C and its methods are independent of one another. It is done for performance, I guess.

So depending on little what you want to do with your subclassed dict you could go with MutableMapping as suggested in https://stackoverflow.com/a/3387975/14536215 or with UserDict (which is a subclass of MutableMapping) such as:

from abc import ABC, abstractmethod
from collections import UserDict


class BaseABC(ABC):

    @abstractmethod
    def hello(self):
        pass

class Child(BaseABC, UserDict):
    pass


child = Child()
Tzane
  • 2,752
  • 1
  • 10
  • 21
  • 1
    Maybe i missed it on the links but i can't find any explanation on why inheriting from dict would prevent the requirement of implementing the abstract method? – tbjorch Feb 12 '21 at 15:16
  • do you want the dictionary to be local to the class or shared by class like a static variable – Golden Lion Feb 12 '21 at 16:18
  • Thanks for that Tzane. Ok, seems I chose a bad case, I thought dict would be sufficiently generic. Seems to work on my own custom class, let's hope it works on the class I need in practice! – kerzane Feb 12 '21 at 16:34
  • @tbjorch I don't think it was explicitly said why this doesn't work, but both sources reference the back end implementation of `dict` ( `list` and `set`) is somehow made "static" to gain better performance. – Tzane Feb 15 '21 at 10:36