Filip Szczybura
Filip Szczybura

Reputation: 427

Problems with multiple inheritance in Python

I have a fundamental class called MetaFunction

class MetaFunction(metaclass=ABCMeta):

    def __init__(
            self,
            pickle_data: PickleData,
            eth_protocols: Protocols = (),
            spi_protocols: Protocols = ()
    )

Class AEB inherits from MetaFunction:

class AEB(MetaFunction):

    def __init__(
            self,
            pickle_data: PickleData,
            eth_protocols: Protocols = (),
            spi_protocols: Protocols = (),
    ):
                    super().__init__(
                pickle_data=pickle_data,
                eth_protocols=eth_protocols,
                spi_protocols=spi_protocols
            )

But there is also a second base class except MetaFunction called EventFinder:

class EventFinder:
    def __init__(self, pickle_filename, export_path):

The final child class that I want to create is AEBEventFinder:

class AEBEventFinder(AEB, EventFinder):
    def __init__(
            self,
            pickle_filename: str,
            export_path: str,
            pickle_data: PickleData,
            eth_protocols: Protocols = (),
            spi_protocols: Protocols = ()
    ):
        AEB.__init__(
            self,
            pickle_data=pickle_data,
            eth_protocols=eth_protocols,
            spi_protocols=spi_protocols,
        )
        EventFinder.__init__(
            self,
            pickle_filename=pickle_filename,
            export_path=export_path
        )

As you can see it inherits from both AEB and EventFinder classes. I solved it using the old approach. None of these worked for me: Calling parent class __init__ with multiple inheritance, what's the right way?

    super().__init__(
        pickle_data=pickle_data,
        eth_protocols=eth_protocols,
        spi_protocols=spi_protocols,
    )
    super(EventFinder, self).__init__(
        pickle_filename=pickle_filename,
        export_path=export_path
    )

According to the link above, I get the following error: TypeError: object.init() takes exactly one argument (the instance to initialize)

How can I solve it using the appropriate 'new' pythonic way?

SOLVED Added **kwargs to each parent class (MetaFunction, AEB, EventFinder) and it worked. No implicit super().init() call in each parent class is needed! ;)

Upvotes: 1

Views: 389

Answers (1)

Chris Wesseling
Chris Wesseling

Reputation: 6368

You should change your parent classes to accept all keyword arguments and just use the ones they recognize. And then you can use super as intended:

from abc import ABCMeta
PickleData = Protocols = object

class MetaFunction(metaclass=ABCMeta):
    def __init__(
        self,
        pickle_data: PickleData,
        eth_protocols: Protocols = (),
        spi_protocols: Protocols = (),
        **kwargs,
    ):
        super().__init__(
            pickle_data=pickle_data,
            eth_protocols=eth_protocols,
            spi_protocols=spi_protocols,
            **kwargs,
        )

        
class AEB(MetaFunction):

    def __init__(
        self,
        pickle_data: PickleData,
        eth_protocols: Protocols = (),
        spi_protocols: Protocols = (),
        **kwargs,
    ):
        super().__init__(
            pickle_data=pickle_data,
            eth_protocols=eth_protocols,
            spi_protocols=spi_protocols,
            **kwargs,
            )

        
class EventFinder:
    foo = 'foo'
    def __init__(self, pickle_filename, export_path, **kwargs):
        self.bar = 'bar'        

        
class AEBEventFinder(AEB, EventFinder):
    def __init__(self, my_own_argument, **kwargs):
        super().__init__(**kwargs)
        # do something with my_own_argument
        
mytest = AEBEventFinder(pickle_data=None, pickle_filename='fn', export_path='.', my_own_argument='blah')
assert mytest.foo == 'foo'
assert mytest.bar == 'bar'

If the parent classes are beyond your control and are uncooperative by not accepting arguments they don't recognize, you can write an adapter that wraps them.

Raymond Hettinger has given a great primer "Super considered super" at PyCon.

Upvotes: 1

Related Questions