If i execute a code like this,
#Code sample 1
class Robot:
def greet(self):
print("I am a robot")
class Android(Robot):
def greet(self):
super().greet()
print("I am an android")
class PersonalAssistant(Robot):
def greet(self):
super().greet()
print("I am a personal assistant")
class AssistantAndroid(Android, PersonalAssistant):
def greet(self):
super().greet()
The output is
I am a robot
I am a personal assistant
I am an android
None
Why the personal assistant is printed before the android?
The MRO of AssistantAndroid is (<class '__main__.AssistantAndroid'>, <class '__main__.Android'>, <class '__main__.PersonalAssistant'>, <class '__main__.Robot'>, <class 'object'>)
So first we go to the Android and first found super in Android which make us go to robot then why the code goes to PersonalAssistant instead of execute the next print(I am an android) in Android?
Moreover, could someone teach me where does the None comes from?
If the super moved into the next line of print() in the subclass like this.
#Code sample 2
class Person:
def print_message(self):
print("Message from Person")
class Student(Person):
def print_message(self):
print("Message from Student")
super().print_message()
class Programmer(Person):
def print_message(self):
print("Message from Programmer")
super().print_message()
class StudentProgrammer(Student, Programmer):
def print_message(self):
super().print_message()
The the output looks in correct order as MRO.
jack = StudentProgrammer()
jack.print_message()
# Message from Student
# Message from Programmer
# Message from Person
But why the #Code sample 1 execute order so strange?
I have added some additional prints here and things are more weird to me..
class Robot:
def greet(self):
print("Start robot")
print("I am a robot")
print("Finish robot")
class Android(Robot):
def greet(self):
print("Start Android")
super().greet()
print("I am an android")
print("Finish Android")
class PersonalAssistant(Robot):
def greet(self):
print("Start PersonalAssistant")
super().greet()
print("I am a personal assistant")
print("Finish PersonalAssistant")
class AssistantAndroid(Android, PersonalAssistant):
def greet(self):
print("Start AssistantAndroid")
super().greet()
print("Finish AssistantAndroid")
a = AssistantAndroid()
print('AssistantAndroid', AssistantAndroid.__mro__)
print('Android', Android.__mro__)
print('PersonalAssistant', PersonalAssistant.__mro__)
print("--------------------")
print(a.greet())
The output is
Start AssistantAndroid
Start Android
Start PersonalAssistant
Start robot
I am a robot
Finish robot
I am a personal assistant
Finish PersonalAssistant
I am an android
Finish Android
Finish AssistantAndroid
None
Does this means, when the execute goes to the level 2 classes( Android and PersonalAssistant), it only execute one line in Android and then one line in PersonalAssistant, then when it executes the super() in Android?? and it means execute the robot and then after finish the robot, it goes to second line in PersonalAssistant which is also means robot, then it skipped it??, then why finish PersonalAssistant and then finish the Android...I am totally confused..
Very appreciate to the answer from @Blckknght
Please refer to his answer I think it explains very well.
Basically, when the Multiple inheritance comes, the only relation you should follow is the MRO order. (The reverse of MRO) So this is why after the Start Android
follows Start PersonalAssistant
but not Start robot
because from the reverse of MRO, the PersonalAssistant becomes the father of Android. So the super() in Android will call the the PersonalAssistant but not robot.
Correct me if my understanding is wrong.
When all of your greet
methods call super().greet
before printing their own text, the output will come in the reverse of the MRO (excluding object
, since it doesn't have a greet
method).
Think about the call stack, where each method waits for the super().greet
call to return before going on to print
. Here's what it looks like, with indentation indicating the depth of the stack:
# in AssistantAndroid.greet()...
super().greet() # resolves to Android.greet() when self is an AssistantAndroid
# in Android.greet()...
super().greet() # resolves to PersonalAssitant.greet() when self is an AssistantAndroid
# in PersonalAssistant.greet()...
super().greet() # resolves to Robot.greet() when self is an AssistantAndroid
# in Robot.greet(), where there's no super() call
print("I am a robot")
# continuing PersonalAssistant.greet()
print("I am a personal assistant")
# continuing Android.greet()
print("I am an android")
# continuing AssistantAndroid.greet(), but there's nothing left to do