Search code examples
pythonabstract-classmultiple-inheritance

Python: How to create an ABC that inherits from others ABC?


I am trying to create a simple abstract base class Abstract that along with its own methods provides the methods of two others abstract base classes: Publisher and Subscriber. When I try to initialize the concrete class Concrete, built on Abstract I get this error: Cannot create a consistent method resolution order (MRO) for bases ABC, Publisher, Subscriber. What is the right way to do it?

from abc import ABC, abstractmethod

class Publisher(ABC):
    
    subscribers = set() 
    
    def register(self, obj):
        self.subscribers.add(obj)
    
    def unregister(self, obj):
        self.subscribers.remove(obj)
    
    def dispatch(self, event):
        print("dispatching", event)
        

class Subscriber(ABC):
    
    @abstractmethod
    def handle_event(self, event):
        raise NotImplementedError
        

class Abstract(ABC, Publisher, Subscriber):
    
    @abstractmethod
    def do_something(self, event):
        raise NotImplementedError
        

class Concrete(Abstract):

    def handle_event(self, event):
        print("handle_event")
    
    def do_something(self, event):
        print("do_something")
    
    

c = Concrete()

Solution

  • Abstract classes don't have to have abc.ABC in their list of bases. They have to have abc.ABCMeta (or a descendant) as their metaclass, and they have to have at least one abstract method (or something else that counts, like an abstract property), or they'll be considered concrete. (Publisher has no abstract methods, so it's actually concrete.)

    Inheriting from ABC is just a way to get ABCMeta as your class's metaclass, for people more comfortable with inheritance than metaclasses, but it's not the only way. You can also inherit from another class with ABCMeta as its metaclass, or specify metaclass=ABCMeta explicitly.


    In your case, inheriting from Publisher and Subscriber will already set Abstract's metaclass to ABCMeta, so inheriting from ABC is redundant. Remove ABC from Abstract's base class list, and everything should work.

    Alternatively, if you really want ABC in there for some reason, you can move it to the end of the base class list, which will resolve the MRO conflict - putting it first says you want ABC methods to override methods from the other classes, which conflicts with the fact that the other classes are subclasses of ABC.