Ver índice de contenidos del libro

15.2. Herencia

La herencia es un mecanismo de la programación orientada a objetos que sirve para crear clases nuevas a partir de clases preexistentes. Se toman (heredan) atributos y comportamientos de las clases viejas y se los modifica para modelar una nueva situación.

La clase vieja se llama clase base y la que se construye a partir de ella es una clase derivada.

Por ejemplo, a partir de una clase Persona (que contenga como atributos identificacion, nombre, apellido) podemos construir la clase AlumnoFIUBA que extiende a Persona y agrega como atributo el padron.

Para indicar el nombre de la clase base, se la pone entre paréntesis a continuación del nombre de la clase (en lugar de la expresión object que poníamos anteriormente; en realidad object es el nombre de la clase base genérica).

Definimos Persona:

class Persona(object):
    "Clase que representa una persona."
    def __init__(self, identificacion, nombre, apellido):
        "Constructor de Persona"
        self.identificacion = identificacion
        self.nombre = nombre
        self.apellido = apellido
    def __str__(self):
        return " %s: %s, %s" %
            (str(self.identificacion), self.apellido, self.nombre)

A continuación definimos AlumnoFIUBA como derivada de Persona, de forma tal que inicialice el nuevo atributo, pero a su vez utilice la inicialización de Persona para las atributos de la clase base:

class AlumnoFIUBA(Persona):
    "Clase que representa a un alumno de FIUBA."
    def __init__(self, identificacion, nombre, apellido, padron):
        "Constructor de AlumnoFIUBA"
        # llamamos al constructor de Persona
        Persona.__init__(self, identificacion, nombre, apellido)
        # agregamos el nuevo atributo
        self.padron = padron

Probamos la nueva clase:

>>> a = AlumnoFIUBA("DNI 35123456", "Damien", "Thorn", "98765")
>>> print a
DNI 35123456: Thorn, Damien

Vemos que se heredó el método __str__ de la clase base. Si queremos, podemos redefinirlo:

def __str__(self):
    "Devuelve una cadena representativa del alumno"
    return " %d: %s, %s" %
        (str(self.padron), self.apellido, self.nombre)

Volvemos a probar:

>>> a = AlumnoFIUBA("DNI 35123456", "Damien", "Thorn", "98765")
>>> print a
98765: Thorn, Damien

De una clase base se pueden construir muchas clases derivadas, así como hemos derivado alumnos, podríamos derivar docentes, empleados, clientes, proveedores, o lo que fuera necesario según la aplicación que estemos desarrollando.

Nota En el diseño de jerarquías de herencia no siempre es del todo fácil decidir cuándo una clase debe extender a otra. La regla práctica para decidir si una clase (S) puede ser definida como heredera de otra (T) es que debe cumplirse que "S es un T". Por ejemplo, Perro es un Animal, pero Vehículo no es un Motor.

Esta regla se desprende del principio de sustitución de Liskov (formulado por Barbara Liskov y Jeannette Wing).

Barbara Liskov es una mujer importante en la historia de la informática, no sólo por este principio, sino que fue la primera mujer en recibir un doctorado en las ciencias de la computación, creadora de varios lenguajes y actualmente es profesora e investigadora del MIT.

En el caso de Python, también se puede construir una clase derivada a partir de varias clases base (por ejemplo, un ayudante de segunda en la UBA es un alumno que también trabaja de docente). Esta posbilidad se llama Herencia Múltiple, pero no la detallaremos por ahora.

La clase de las figuras

Un ejemplo clásico de herencia es el de las figuras cerradas en el plano, con un método para calcular el área. En este caso, la clase base no tiene comportamiento definido ni atributos, dado que cada figura tiene atributos muy distintos (radio en el caso del círculo, base y altura en el caso del triángulo, etc.), y en cuanto al cálculo del área, cada figura tiene una fórmula diferente:

La clase base:

class Figura(object):
    """ Una figura en el plano. """
    def area(self):
        " Este método debe ser redefinido. "
        pass

Los círculos:

from math import pi
 
class Circulo(Figura):
    """ Un círculo en el plano. """
    def __init__(self, radio=0):
        " Constructor de círculo. "
        self.radio = radio
 
    def area(self):
        " Devuelve el área del círculo. "
        return pi * self.radio * self.radio

Y los triángulos:

class Triangulo(Figura):
    """ Un triángulo en el plano. """
    def __init__(self, base=0, altura=0):
        " Constructor de triángulo. "
        self.base = base
        self.altura = altura
 
    def area(self):
        " Devuelve el área del triángulo. "
        return self.base * self.altura / 2.

Y ahora las pruebas:

>>> c = Circulo(4)
>>> c.area()
50.26548245743669
>>>
>>> t = Triangulo(3, 5)
>>> t.area()
7.5
Copyright (c) 2011-2014 Rosita Wachenchauzer, Margarita Manterola, Maximiliano Curia, Marcos Medrano, Nicolás Paez. La copia y redistribución de esta página se permite bajo los términos de la licencia Creative Commons Atribución - Compartir Obras Derivadas Igual 3.0 siempre que se conserve esta nota de copyright.