11.1 Method Resolution Order
El orden de resolución de métodos (Method Resolution Order, MRO) determina la secuencia en la que Python busca métodos y atributos en la jerarquía de clases. Esto es especialmente importante cuando trabajamos con herencia múltiple, donde una clase puede heredar atributos y métodos de varios clases madre.
Básicamente, existe un orden estricto (o más bien, un algoritmo) según el cual Python recorre el árbol de herencia de clases. Este algoritmo asegura un orden de búsqueda de métodos correcto, que se puede describir de la siguiente manera:
Algoritmo de linealización C3
El algoritmo de linealización C3 determina el MRO combinando:
- La propia clase.
- La lista de clases madre en el orden en que se enumeran.
- MRO de las clases madre en el mismo orden.
Reglas del algoritmo de linealización C3
-
Mantener el orden local de los métodos: si la clase
A
se menciona antes de la claseB
, todos los métodos de la claseA
deben ser considerados antes de los métodos de la claseB
. -
Respetar el orden en las clases madre: si la clase
A
es padre de la claseB
, todos los métodos de la claseA
deben ser considerados antes que los métodos de la claseB
. -
Respetar el orden de herencia: si la clase
C
es padre de dos o más clases, el orden de los métodos de la claseC
debe preservarse en el MRO de todas esas clases.
Pasos del algoritmo:
Paso 1. Comenzamos con la propia clase:
Siempre comenzamos con la propia clase donde se llama al método.
Paso 2. Añadimos las clases base en el orden en que se enumeran:
Después de la clase actual, revisamos las clases base en el orden en que están indicadas en la herencia.
Paso 3. Recorremos las clases madre:
Buscamos campos y métodos allí.
Paso 4. Combinamos el MRO de las clases madre:
Si una misma clase base se hereda a través de varios caminos, se revisa solo una vez y en el orden correcto (todas las demás veces se omitirá).
Para aquellos ya familiarizados con el tema "Algoritmos y estructuras de datos", esto es una búsqueda en profundidad, no en amplitud.
11.2 Comprobación del MRO
En Python, se puede comprobar el orden de búsqueda de métodos y campos de una clase,
usando el atributo __mro__
o la función
mro()
.
Ejemplo:
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
class C(A):
def method(self):
print("C")
class D(B, C):
def method(self):
print("D")
# Comprobación del MRO
print(D.__mro__)
La salida será:
(<class '__main__.D'>,
<class '__main__.B'>,
<class '__main__.C'>,
<class '__main__.A'>,
<class 'object'>)
Esto muestra el orden en el que Python buscará métodos y atributos:
D
: Python primero comprueba el método en la claseD
.-
B
: Luego, Python comprueba el método en la claseB
(la primera clase madre). -
C
: Si el método no se encuentra en la claseB
, Python comprueba el método en la claseC
(la segunda clase madre). -
A
: Si el método no se encuentra en las clasesB
yC
, Python comprueba el método en la claseA
. -
object
: Finalmente, Python comprueba el método en la clase baseobject
.
11.3 Uso de super()
con MRO
La función super()
sigue el MRO para llamar a los métodos
de las clases madre en el orden correcto. Consideremos un ejemplo de uso de
super()
:
class A:
def method(self):
print("A")
super().method()
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
class D(B, C):
def method(self):
print("D")
super().method()
d = D()
d.method()
La salida será la siguiente:
D
B
C
A
Orden de búsqueda (MRO)
1. Llamada al método method
de la clase D
:
- Python primero comprueba el método en la clase
D
y lo encuentra allí. - El método
D.method()
se ejecuta y muestra"D"
. -
Luego se llama a
super().method()
, que sigue el MRO para llamar al siguiente método.
2. Llamada al método method
de la clase B
:
- Según el MRO, la siguiente clase después de
D
esB
. - El método
B.method()
se ejecuta y muestra"B"
. -
Luego se llama a
super().method()
, que sigue el MRO para llamar al siguiente método.
3. Llamada al método method
de la clase C
:
- La siguiente clase en el MRO después de
B
esC
. - El método
C.method()
se ejecuta y muestra"C"
. -
Luego se llama a
super().method()
, que sigue el MRO para llamar al siguiente método.
4. Llamada al método method
de la clase A
:
- La siguiente clase en el MRO después de
C
esA
. - El método
A.method()
se ejecuta y muestra"A"
. -
Luego se llama a
super().method()
, pero comoA
no tiene métodos padresmethod
(exceptoobject
), la llamada termina sin más acciones.
GO TO FULL VERSION