Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python multiple inheritance, calling base class function

I was just trying something with multiple inheritance in python. I come up with this

class ParentOne:
    def foo(self):
        print("ParentOne foo is called")

class ParentTwo:
    def foo(self):
        print("ParentTwo foo is called")

class Child(ParentOne, ParentTwo):

    # how is this working
    def call_parent_two_foo(self):
        super(ParentOne, self).foo()

    # This does not work
    def call_parent_foo(self):
        super(ParentTwo, self).foo()

    def call_super_foo(self):
        super(Child, self).foo()

    def foo(self):
        print("Child foo is called")


if __name__ == "__main__":
    child = Child()
    child.foo()
    child.call_super_foo()
    child.call_parent_two_foo()

    # child.call_parent_foo() #This gives the below error
    # super(ParentTwo, self).foo()
    # AttributeError: 'super' object has no attribute 'foo'

and it gives the following output

Child foo is called
ParentOne foo is called
ParentTwo foo is called

I am getting confused as to how calling of super(ParentOne, self).foo() is evaluated in this case. As per my understanding ParentOne class does not have any idea of the methods and attributes of ParentTwo class. How does super works in case of multiple inheritance

like image 382
Anurag Sharma Avatar asked Jan 04 '23 20:01

Anurag Sharma


1 Answers

Python constructs a method resolution order (MRO) when it builds a class. The MRO is always linear. If python cannot create a linear MRO, then a ValueError will be raised. In this case, your MRO probably looks like:

Child -> ParentOne -> ParentTwo -> object

Now when python see's a super(cls, self), it basically looks at self and figures out the MRO. It then uses cls to determine where we are currently at in the MRO and finally it returns an object which delegates to the next class in the MRO. So, in this case, a super(Child, self) call would return an object that delegates to ParentOne. A super(ParentOne, self) class would return an object that delegates to ParentTwo. Finally a super(ParentTwo, self) call would delegate to object. In other words, you can think of super as a fancier version of the following code:

def kinda_super(cls, self):
    mro = inspect.getmro(type(self))
    idx = mro.index(cls)
    return Delegate(mro[idx + 1])  # for a suitably defined `Delegate`

Note that since super(ParentTwo, self) returns a "Delegate" to object, we can see why you're getting an AttributeError when you try super(ParentTwo, self).foo() -- Specifically the reason is because object has no foo method.

like image 126
mgilson Avatar answered Jan 07 '23 12:01

mgilson