Method Resolution Order(MRO) it denotes the way a programming language resolves a method or attribute. Python supports classes inheriting from other classes. The class being inherited is called the Parent or Superclass, while the class that inherits is called the Child or Subclass.
To get the MRO of a class, you can use either the __mro__ attribute or the mro() method. The __mro__ attribute returns a tuple, but the mro() method returns a python list. To take a more complex example that also demonstrates depth-first search, we take 6 classes.
Two built-in functions isinstance() and issubclass() are used to check inheritances. The function isinstance() returns True if the object is an instance of the class or other classes derived from it. Each and every class in Python inherits from the base class object .
Follow along...:
>>> class A(object): pass
...
>>> A.__mro__
(<class '__main__.A'>, <type 'object'>)
>>> class B(A): pass
...
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
>>> class C(A): pass
...
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
>>>
As long as we have single inheritance, __mro__
is just the tuple of: the class, its base, its base's base, and so on up to object
(only works for new-style classes of course).
Now, with multiple inheritance...:
>>> class D(B, C): pass
...
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
...you also get the assurance that, in __mro__
, no class is duplicated, and no class comes after its ancestors, save that classes that first enter at the same level of multiple inheritance (like B and C in this example) are in the __mro__
left to right.
Every attribute you get on a class's instance, not just methods, is conceptually looked up along the __mro__
, so, if more than one class among the ancestors defines that name, this tells you where the attribute will be found -- in the first class in the __mro__
that defines that name.
mro()
stands for Method Resolution Order. It returns a list of types the class is derived from, in the order they are searched for methods.
mro()
and __mro__
work only on new style classes. In Python 3, they work without any issues. In Python 2, however, those classes need to inherit from object
.
This would perhaps show the order of resolution.
class A(object):
def dothis(self):
print('I am from A class')
class B(A):
pass
class C(object):
def dothis(self):
print('I am from C class')
class D(B, C):
pass
d_instance= D()
d_instance.dothis()
print(D.mro())
and response would be
I am from A class
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>]
The rule is depth-first, which in this case would mean D, B, A, C.
Python normally uses a depth-first order when searching inheriting classes, but when two classes inherit from the same class, Python removes the first mention of that class from mro.
Order of resolution will be different in diamond inheritance.
class A(object):
def dothis(self):
print('I am from A class')
class B1(A):
def dothis(self):
print('I am from B1 class')
# pass
class B2(object):
def dothis(self):
print('I am from B2 class')
# pass
class B3(A):
def dothis(self):
print('I am from B3 class')
# Diamond inheritance
class D1(B1, B3):
pass
class D2(B1, B2):
pass
d1_instance = D1()
d1_instance.dothis()
# I am from B1 class
print(D1.__mro__)
# (<class '__main__.D1'>, <class '__main__.B1'>, <class '__main__.B3'>, <class '__main__.A'>, <class 'object'>)
d2_instance = D2()
d2_instance.dothis()
# I am from B1 class
print(D2.__mro__)
# (<class '__main__.D2'>, <class '__main__.B1'>, <class '__main__.A'>, <class '__main__.B2'>, <class 'object'>)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With