nico9T
nico9T

Reputation: 2736

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

Upvotes: 7

Views: 3240

Answers (3)

Injae Lee
Injae Lee

Reputation: 1

class Abstract(Publisher, Subscriber, ABC):

this would be the solution if you want to make sure the class is not instantiable

Upvotes: 0

user2357112
user2357112

Reputation: 282198

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.

Upvotes: 7

Sazzy
Sazzy

Reputation: 1994

Change from this:

class Abstract(ABC, Publisher, Subscriber):

To this:

class Abstract(Publisher, Subscriber):

The two subclasses are already abstract, thus you don't need to inherit from ABC again.

Upvotes: 3

Related Questions