Anuncios

Bienvenidos sean a este post, hoy veremos como se ordena python para encontrar el metodo de un objeto.

Anuncios
Anuncios

Cuando hablamos de shadowing en este post, vimos como python al no encontrar un elemento de la clase creadora del objeto, este seguia subiendo en la cadena de herencia hasta encontrarlo o simplemente devolver una excepcion de que no se encontro pero esto es simple cuando tenemos herencia simple sin embargo cuando tenemos herencias multiples esto se vuelve mas complejo dado que no tenemos una forma directa de poder descubrir por donde proseguira con la busqueda, aunque python nos provee una forma de poder buscar internamente el orden de las clases denominado MRO (Orden de Resolucion del Metodo por sus siglas en ingles), para ver este concepto vamos a tomar el ejemplo del post anterior, veamos como es el codigo de todas las clases:

>>> class Forma:
...     tipo_geometrico = 'Forma Generica'
...     def area(self):
...             raise NotImplementedError
...     def get_tipo_geometrico(self):
...             return self.tipo_geometrico
... 
>>> class Trazador:
...     def trazar(self, ratio, topleft):
...             print('Trazando un {}, ratio {}.'.format(
...                     
>>> class Poligono(Forma, Trazador):
...     tipo_geometrico = 'Poligono'
... 
>>> class PoligonoComun(Poligono):
...     tipo_geometrico = 'Poligono Comun'
...     def __init__(self, lado):
...             self.lado = lado
... 
>>> class HexagonoComun(PoligonoComun):
...     tipo_geometrico = 'Hexagono Comun'
...     def area(self):
...             return 1.5 * (3 ** .5 * self.lado ** 2)
... 
>>> class Cuadrado(PoligonoComun):
...     tipo_geometrico = 'Cuadrado'
...     def area(self):
...             return self.lado * self.lado
... 
>>>
Anuncios

Esto se los comparto por si no lo tienen creado anteriormente, una vez creadas todas las clases vamos a ejecutar la siguiente accion:

>>> print(cuadrado.__class__.__mro__)
Anuncios

Esto nos devolvera la siguiente salida:

(<class '__main__.Cuadrado'>, <class '__main__.PoligonoComun'>, 
 <class '__main__.Poligono'>, <class '__main__.Forma'>, 
 <class '__main__.Trazador'>, <class 'object'>)
Anuncios

En la salida podemos ver como pasa por todas las clases y nos devuelve el orden que mejor interpreta el lenguaje para pasar por las mismas hasta llegar a la clase especial llamada object, vamos a crear un nuevo ejemplo para entender el concepto anterior, agreguemos las siguientes clases:

>>> class A:
...     etiqueta = 'a'
... 
>>> class B(A):
...     etiqueta = 'b'
... 
>>> class C(A):
...     etiqueta = 'c'
... 
>>> class D(B, C):
...     pass
... 
>>>
Anuncios

Tenemos una clase base llamada A, despues dos hijas de esta llamadas B y C, para finalmente tener una de multiple herencia llamada D y sera hija de B y C, en las tres anteriores tenemos una variable llamada etiqueta con distintos valores pero en D usamos pass para que tome los valores de los padres, vamos a crear un objeto nuevo:

>>> d = D()
Anuncios

Pasemos a probarlo para ver que obtenemos:

>>> print(d.etiqueta)
b
>>>
Anuncios

Deberia haber devuelto el valor de la clase B o C pero como vemos nos devuelve el valor de la clase B, vamos a usar a __mro__ para ver su estructura:

>>> print(d.__class__.__mro__)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>>
Anuncios

Como podemos ver la primer clase que encuentra es la B, por lo tanto encuentra ese valor y como cumple nuestra necesidad es la que muestra, si cambiamos el orden nos devolvera el valor de etiqueta, vamos a realizar una pequeña modificacion en la clase B:

>>> class B(A):
...     pass
... 
>>>
Anuncios

En este caso volvemos a crear la clase B donde quitaremos el valor de etiqueta y dejaremos la clase en blanco, el siguiente paso sera volver a crear la clase D para que actualice los nuevos valores:

>>> class D(B, C):
...     pass
... 
>>>
Anuncios

Y debemos volver a definir nuevamente a la instancia de la clase D que generamos anteriormente y por ultimo volvemos a imprimir el valor de la etiqueta de esta instancia:

>>> print(d.etiqueta)
c
>>>
Anuncios

Ahora nos imprimio el valor de la clase C porque ahora no existe un valor en la clase B, pasemos a ejecutar nuevamente el __mro__ para ver que nos devuelve:

>>> print(d.__class__.__mro__)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>>
Anuncios

Como podemos ver se sigue manteniendo el orden anterior pero como dijimos antes al no encontrar un valor dentro de la clase B procede a la clase C y nos devuelve el valor que coinicide con nuestra necesidad, es decir que siempre habra un orden generado por el lenguaje y este para las herencias multiples estara sujeto al orden que pasamos para las clases bases de nuestra clase hija.

Anuncios
Nota: Prueben de crear a la clase D con distintos orden de las clases para ver que sucede.
Anuncios

En resumen, hoy hemos visto que es mro, orden de resolucion de metodos, como este se encarga de mantener un orden entre todas las clases, tambien vimos como este evalua para ordenar los casos de las herencias multiples, tambien como trabaja en el fondo, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50