0

Suppose you have abstract classes A1 and A2. Each of them has an abstract method and a concrete method.

from abc import ABC, abstractmethod

class A0(ABC):
    pass

class A1(A0, ABC):
    def foo(self):
        return 1

    @abstractmethod
    def bar(self):
        raise NotImplementedError()


class A2(A0, ABC):
    @abstractmethod
    def foo(self):
        raise NotImplementedError()
    
    def bar(self):
        return 10

Now you want to mix-in them togather to implement each other's abstract method:

class C(A2, A1, A0):
    def all(self):
        return (super().foo(), super().bar())


C().all()

However the above code does not work because I got the following error:

TypeError: Can't instantiate abstract class C with abstract method foo

How can I create C so that it can mix-in both A1 and A2?

Yang Bo
  • 3,586
  • 3
  • 22
  • 35

2 Answers2

1

I moved the abstract methods to A0, and only implemented one of each in the A1, A2 classes, then C has both of them implemented:

from abc import ABC, abstractmethod

class A0(ABC):
    @abstractmethod
    def foo(self):
        raise NotImplementedError()

    @abstractmethod
    def bar(self):
        raise NotImplementedError()

class A1(A0, ABC):
    def foo(self):
        return 1

class A2(A0, ABC):
    def bar(self):
        return 10

class C(A1,A2):
    def all(self):
        return (super().foo(), super().bar())


print(C().all())
# can't instantiate A0,A1,A2, as these have not implemented abstract methods
# print(A1()) # won't work
# print(A2()) # won't work
Gábor Fekete
  • 1,343
  • 8
  • 16
  • Moving abstract methods to `A0` would change `A0`'s functionality. I would move them to new `ABC`'s instead. – Yang Bo Aug 22 '23 at 19:23
0

This is a solution similar to Gábor Fekete, except that the abstract methods are extracted to new ABC's, to avoid changing A0.

from abc import ABC, abstractmethod

class A0(ABC):
    pass

class AbstractFoo(A0, ABC):
    @abstractmethod
    def foo(self):
        raise NotImplementedError()

class AbstractBar(A0, ABC):
    @abstractmethod
    def bar(self):
        raise NotImplementedError()

class A1(AbstractFoo, AbstractBar, A0, ABC):
    def foo(self):
        return 1

class A2(AbstractFoo, AbstractBar, A0, ABC):
    def bar(self):
        return 10

class C(A2, A1, A0):
    def all(self):
        return (super().foo(), super().bar())

C().all()

Yang Bo
  • 3,586
  • 3
  • 22
  • 35