1

Here is a simplified code of my main code illustrating the behaviour I obtain.

Suppose I have a main class (MAIN) and two classes (A,B) inheriting from it. This main class has a method which is overwriten by A but not by B, which means that B inherits the method from main.

Then I have a class D which inherits from A and from B, and has a method which calls the aforementioned method. From what I have understood in the way multiple inheritance work, if I define D as class D(A,B) then if A and B have a shared method, calling D.method() will call A.method, and vice-versa (i.e if class D(B,A) then B.method is called. The following code exemplifies this text.


class MAIN(object):
    def __init__(self):
        pass
    def print(self):
        print('HELLO MAIN')

class A(MAIN):
    def __init__(self):
        pass
    def print(self):
        print('HELLO A')

class B(MAIN):
    def __init__(self):
        pass


class C(A,B):
    def __init__(self):
        pass

    def Cprint(self):
        self.print()

c = C()

c.Cprint()


class C(B,A):
    def __init__(self):
        pass

    def Cprint(self):
        self.print()

c = C()

c.Cprint()

However this code always print 'HELLO A', i.e even in the case class C(B,A) I don't get a HELLO MAIN as I would expect. What is happening here? Thanks so much in advance

2 Answers 2

3

The mro is (C, A, B, MAIN) with class C(A, B) and (C, B, A, MAIN) with class C(B, A). In both cases, A is before MAIN. B doesn't define .print, so it doesn't matter.

The method uplooks works like this: (pseudo code)

def find_attribute(obj, name):
    if name in obj.__dict__:
        return obj.__dict__[name]
    mro = type(obj).__mro__
    for cls in mro:
        if name in cls.__dict__:
            return cls.__dict__[name] # (Here a bit more magic for descriptors happens)
    raise AttributeError(name)

For the classes this is what their __dict__ look like:

MAIN.__dict__ = {"print": <method MAIN.print>}
A.__dict__ = {"print": <method A.print>}
B.__dict__ = {}
C.__dict__ = {"Cprint": <method C.Cprint>}

As you can see, B does not have a print defined, so in mro=(C, B, A, MAIN) the first print that does get found is in A.

Sign up to request clarification or add additional context in comments.

7 Comments

You can call C.mro() to see the mro for class C. Note that C must be a class, and not a class instance.
@TomKarzes Yes. I decided to no explain that and instead link to the other question. Way better explanation that I don't need to fully duplicate here.
It's interesting to note that certain inheritance sequences are forbidden. For example, class C(A, MAIN) is allowed, but class C(MAIN, A) gives an error, since it cannot create a consistent mro.
Thanks for the reply. Just one point. If B does not define .print then it should inherit MAIN .print method, then in the case where the mro is (C, B, A, MAIN), 'HELLO MAIN' should be printed. Am I right?
@jdeJuan In the case where the mro is (C, B, A, MAIN), there are two classes that directly define print: A and MAIN. Since A is before MAIN in the mro, it will use A's print method, so you should see HELLO A. Figuring out the mro can be tricky (but Python will tell you, as I explained in my first comment). But once you know the mro, it's trivial to determine which method it will use.
|
0

You are inheriting the Class A everywhere and class A overrrides Main functions print() thats why you dont get the "HELLO MAIN"

class C(B):
    def __init__(self):
        pass

    def Cprint(self):
        self.print()

inherit only B class which does not overrides Main class print function then you will get the HELLO MAIN output

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.