¿Qué hace “mro()”?
-
18-09-2019 - |
Pregunta
En django.utils.functional.py
:
for t in type(res).mro(): # <----- this
if t in self.__dispatch:
return self.__dispatch[t][funcname](res, *args, **kw)
No entiendo mro()
.¿Qué hace y qué significa "mro"?
Solución
Seguir a lo largo...:
>>> 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'>)
>>>
Mientras tengamos herencia única, __mro__
es solo la tupla de:la clase, su base, la base de su base, y así hasta object
(por supuesto, solo funciona para clases de nuevo estilo).
Ahora con múltiple herencia...:
>>> class D(B, C): pass
...
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
...también tienes la seguridad de que, en __mro__
, ninguna clase está duplicada y ninguna clase viene después de sus antecesoras, salvo que las clases que entran primero en el mismo nivel de herencia múltiple (como B y C en este ejemplo) están en el __mro__
de izquierda a derecha.
Cada atributo que obtienes en la instancia de una clase, no sólo los métodos, se busca conceptualmente a lo largo del __mro__
, entonces, si más de una clase entre los ancestros define ese nombre, esto le indica dónde se encontrará el atributo: en la primera clase del __mro__
que define ese nombre.
Otros consejos
mro()
significa Resolución método de pedido. Se devuelve una lista de tipos de la clase se deriva de, en el orden en que se han buscado métodos.
MRO () o __ __ MRO sólo funciona en las nuevas clases de estilo. En Python 3, trabajan sin ningún problema. Pero en Python 2 esas clases tienen que heredar de objetos.
Esto tal vez mostrar el orden de resolución.
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())
y la respuesta sería
I am from A class
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>]
La regla es primero en profundidad, que en este caso significaría D, B, A, C.
Python normalmente utiliza un profundidad-primero orden cuando se busca clases heredado mientras que cuando dos clases heredan de la misma clase, Python quita la primera mención de que clase de MRO.
Orden de resolución será diferente en la herencia de diamantes.
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'>)