6.2.5 Herencia

6.2.5 Herencia

Nivel intermedio

La herencia consiste en crear una nueva clase partiendo de una clase existente, pero que añade o modifica ciertos aspectos. Se considera una buena práctica tanto para reutilizar código como para realizar generalizaciones.

6.2.5 Herencia

Figura 13: Nomenclatura de clases en la herencia

Nota: Cuando se utiliza herencia, la clase derivada, de forma automática, puede usar todo el código de la clase base sin necesidad de copiar nada explícitamente.

Heredar desde una clase base

Para que una clase «herede» de otra, basta con indicar la clase base entre paréntesis en la definición de la clase derivada.

Sigamos con el ejemplo. Una de las grandes categorías de droides en StarWars es la de droides de protocolo. Vamos a crear una herencia sobre esta idea:

6.2.5 Herencia

Vamos a añadir un par de métodos a la clase base, y analizar su comportamiento:

6.2.5 Herencia

6.2.5 Herencia

Sobreescribir un método

Como hemos visto, una clase derivada hereda todo lo que tiene su clase base. Pero en muchas ocasiones nos interesa modificar el comportamiento de esta herencia.

En el ejemplo vamos a modificar el comportamiento del método switch_on() para la clase derivada:

6.2.5 Herencia

Añadir un método

La clase derivada también puede añadir métodos que no estaban presentes en su clase base. En el siguiente ejemplo vamos a añadir un método translate() que permita a los droides de protocolo traducir cualquier mensaje:

6.2.5 Herencia

Con esto ya hemos aportado una personalidad diferente a los droides de protocolo, a pesar de que heredan de la clase genérica de droides de StarWars.

Accediendo a la clase base

Puede darse la situación en la que tengamos que acceder desde la clase derivada a métodos o atributos de la clase base. Python ofrece super() como mecanismo para ello.

Veamos un ejemplo más elaborado con nuestros droides:

6.2.5 Herencia

6.2.5 Herencia

Herencia múltiple

Nivel avanzado

Aunque no está disponible en todos los lenguajes de programación, Python sí permite que los objetos pueden heredar de múltiples clases base.

Si en una clase se hace referencia a un método o atributo que no existe, Python lo buscará en todas sus clases base. Es posible que exista una colisión en caso de que el método o el atributo buscado esté, a la vez, en varias clases base. En este caso, Python resuelve el conflicto a través del orden de resolución de métodos.

Supongamos que queremos modelar la siguiente estructura de clases con herencia múltiple:

6.2.5 Herencia

6.2.5 Herencia

Figura 14: Ejemplo de herencia múltiple

6.2.5 Herencia

Todas las clases en Python disponen de un método especial llamado mro() que devuelve una lista de las clases que se visitarían en caso de acceder a un método o un atributo. También existe el atributo     mro_________________ como una tupla de esas clases:

6.2.5 Herencia

Veamos el resultado de la llamada a los métodos definidos:

6.2.5 Herencia

Nota: Todos los objetos en Python heredan, en primera instancia, de object. Esto se puede comprobar con el mro() correspondiente:

6.2.5 Herencia

6.2.5 Herencia

Mixins

Hay situaciones en la que nos interesa incorporar una clase base «independiente» de la jerarquía establecida, y sólo a efectos de tareas auxiliares. Esta aproximación podría ayudar a evitar colisiones en métodos o atributos reduciendo la ambigüedad que añade la herencia múltiple. Estas clases auxiliares reciben el nombre de «mixins».

Veamos un ejemplo en el que usamos un «mixin» para mostrar las variables de un objeto:

6.2.5 Herencia

Ejercicio

Dada la siguiente estructura/herencia que representa diferentes clases de ficheros:

6.2.5 Herencia

Se pide lo siguiente:

  1. Cree las 3 clases de la imagen anterior con la herencia señalada.
  2. Cree un objeto de tipo VideoFile con las siguientes características:
  • path: /home/python/vanrossum.mp4
  • codec: h264
  • geoloc: (23.5454, 31.4343)
  • duration: 487
  • dimensions: (1920, 1080)
  1. Añada el contenido ’audio/ogg’ al fichero.
  2. Añada el contenido ’video/webm’ al fichero.
  3. Imprima por pantalla la info() de este objeto (el método info() debería retornar str y debería hacer uso de los métodos info() de las clases base).

Salida esperada:

6.2.5 Herencia

El método size() debe devolver el número total de caracteres sumando las longitudes de los elementos del atributo contents.

Agregación y composición

Aunque la herencia de clases nos permite modelar una gran cantidad de casos de uso en términos de «is-a» (es un), existen muchas otras situaciones en las que la agregación o la composición son una mejor opción. En este caso una clase se compone de otras cases: hablamos de una relación «has-a» (tiene un).

Hay una sutil diferencia entre agregación y composición:

  • La composición implica que el objeto utilizado no puede «funcionar» sin la presencia de su propietario.
  • La agregación implica que el objeto utilizado puede funcionar por sí mismo.

6.2.5 Herencia

Figura 15: Agregación vs. Composición

Veamos un ejemplo de agregación en el que añadimos una herramienta a un droide:

6.2.5 Herencia

6.2.5 Herencia

EJERCICIOS DE REPASO

  1. Escriba una clase en Python para representar una secuencia de ADN. De momento, la
  • 4 atributos de clase, cada uno representando una base nitrogenada con su valor como un carácter.
  • Constructor que recibe una secuencia de caracteres (bases).
  • Método para representar el objeto en formato «string».
  1. Continúe con el ejercicio anterior, y añada a la clase 4 propiedades que calculen el número total de cada una de las bases presentes en la secuencia.
  2. Continúe con el ejercicio anterior, y añada a la clase un método de instancia para sumar dos secuencias de ADN. La suma se hará base a base y el resultado será el máximo de cada letra(base).
  3. Continúe con el ejercicio anterior, y añada a la clase un método de instancia para obtener el porcentaje de aparición de cada base (usando las propiedades definidas en ejercicios anteriores).
  4. Continúe con el ejercicio anterior, y añada a la clase un método de instancia para multiplicar dos secuencias de ADN. La multiplicación consiste en dar como salida una nueva secuencia que contenga sólo aquellas bases que coincidan en posición en ambas secuencias de entrada.

– Solución a todos los ejercicios

AMPLIAR CONOCIMIENTOS

  • Supercharge Your Classes With Python super()
  • Inheritance and Composition: A Python OOP Guide
  • OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods
  • Intro to Object-Oriented Programming (OOP) in Python
  • Pythonic OOP String Conversion:___ repr__ vs____ str___
  • @staticmethod vs @classmethod in Python
  • Modeling Polymorphism in Django With Python
  • Operator and Function Overloading in Custom Python Classes
  • Object-Oriented Programming (OOP) in Python 3
  • Why Bother Using Property Decorators in Python?

Publicaciones Similares