What does "mro()" do?
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'>)