Search code examples
pythonmultiple-inheritanceabc

python ABC & Multiple Inheritance


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"?


Solution

  • 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()