The order in which Python searches for attributes in base classes is called method resolution order(MRO). It gives a linearized path for an inheritance structure.
Python computes an MRO for every class in the hierarchy; this MRO is computed using the ‘C3 linearization algorithm’. This algorithm is quite complicated, you can check the documentation if you are interested in the details but roughly it works in a depth first, left to right manner, and it searches each class only once. For example, in our previous diamond inheritance example, the Person class can be reached in two ways but it will be looked up only once in MRO.
We can see the MRO for any class using the __mro__ attribute or the mro method or by using the help function. If we have an instance and want to see its MRO dynamically, we can use the __class__ attribute.
Here is the code for the diamond example that we have seen. The classes Student and Teacher inherit from class Person, and the class TeachingAssistant inherits from classes Student and Teacher. All the classes have defined a method named greet.
class Person: def greet(self): print("I am a Person") class Teacher(Person): def greet(self): print("I am a Teacher") class Student(Person): def greet(self): print("I am a Student") class TeachingAssistant(Student, Teacher): def greet(self): print("I am a Teaching Assistant")
If we use help on the class TeachingAssistant, we will see MRO for it at the top.
>>> help(TeachingAssistant)
Help on class TeachingAssistant in module aaa: class TeachingAssistant(Student, Teacher) | Method resolution order: | TeachingAssistant | Student | Teacher | Person | builtins.object | | Methods defined here: | | greet(self) | | ---------------------------------------------------------------------- | Data descriptors inherited from Person: | | __dict__ | dictionary for instance variables | | __weakref__ | list of weak references to the object (END)
>>> TeachingAssistant.__mro__ (<class 'aaa.TeachingAssistant'>, <class 'aaa.Student'>, <class 'aaa.Teacher'>, <class 'aaa.Person'>, <class 'object'>) >>> TeachingAssistant.mro() [<class 'aaa.TeachingAssistant'>, <class 'aaa.Student'>, <class 'aaa.Teacher'>, <class 'aaa.Person'>, <class 'object'>] >>> x = TeachingAssistant() >>> x.__class__.__mro__ (<class 'aaa.TeachingAssistant'>, <class 'aaa.Student'>, <class 'aaa.Teacher'>, <class 'aaa.Person'>, <class 'object'>)