Tres entradas de cine con una sola base
La herencia deja que una clase nueva reutilice los atributos y métodos de otra. El polimorfismo deja llamar al mismo método sobre objetos distintos, y cada uno responde a su manera.
Un cine vende entrada normal, de estudiante y VIP. Las tres tienen precio, pero lo calculan distinto. Con herencia escribes lo común una vez y solo cambias lo que difiere.
Al final de esta lección
Nota
Puedo reutilizar código con la herencia y usar el polimorfismo.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Herencia | una clase recibe los atributos y métodos de otra | |
| Superclase | la clase de la que se hereda | |
| Subclase | la clase que hereda de otra | class EntradaVip(Entrada) |
| Sobrescribir | dar a un método heredado un cuerpo nuevo | |
| Polimorfismo | la misma llamada hace cosas distintas según el objeto | |
| super() | da acceso a la versión de la superclase |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una subclase hereda lo de su superclase
Se escribe la superclase entre paréntesis: class EntradaVip(Entrada). La subclase tiene todos los atributos y métodos de Entrada sin copiarlos.
Heredar es decir «es un tipo de». Una entrada VIP es un tipo de entrada. Por eso puede ir en cualquier sitio donde se espere una entrada.
Ejemplo: qué hereda y qué cambia cada clase
| Clase | Qué hereda | Qué cambia | Precio con base de 10 € |
|---|---|---|---|
| Entrada | Nada, es la base | Devuelve el precio base | 10 € |
| EntradaEstudiante | El constructor | Resta 3 € al precio | 7 € |
| EntradaVip | El método precio | Suma 4 € y guarda la bebida | 14 € |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Sobrescribir cambia un método; super() lo amplía
Si la subclase define un método con el mismo nombre, sobrescribe el de la superclase. Python usa el de la subclase.
A veces quieres el resultado original y algo más. super().precio() llama al método de la superclase. En EntradaVip, el precio es el de la entrada más 4 euros.
Tres clases y un mismo método
# El cine vende tres tipos de entrada.
class Entrada:
def __init__(self, precio_base):
self.precio_base = precio_base
def precio(self):
return self.precio_base
class EntradaEstudiante(Entrada):
def precio(self):
return self.precio_base - 3
class EntradaVip(Entrada):
def __init__(self, precio_base, bebida):
super().__init__(precio_base)
self.bebida = bebida
def precio(self):
return super().precio() + 4
for entrada in [Entrada(10), EntradaEstudiante(10), EntradaVip(10, "zumo")]:
print(entrada.precio())
# Cambia el descuento del estudiante a 4 euros y vuelve a ejecutar.
Guarda la familia de entradas en un archivo
En el laboratorio guardas la familia de clases en entradas.py. Luego la usas desde otro archivo, taquilla.py, que suma todas las entradas de una venta.
Antes de pulsar Ejecutar, predice qué imprimirá cada orden. Después compara.
Entra en la carpeta de trabajo
mkdir -p ~/oop && cd ~/oopSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe las tres clases en un archivo
printf 'class Entrada:\n def __init__(self, precio_base):\n self.precio_base = precio_base\n\n def precio(self):\n return self.precio_base\n\n\nclass EntradaEstudiante(Entrada):\n def precio(self):\n return self.precio_base - 3\n\n\nclass EntradaVip(Entrada):\n def __init__(self, precio_base, bebida):\n super().__init__(precio_base)\n self.bebida = bebida\n\n def precio(self):\n return super().precio() + 4\n' > entradas.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Pide el precio a tres objetos distintos
python3 -c "from entradas import Entrada, EntradaEstudiante, EntradaVip; print(Entrada(10).precio(), EntradaEstudiante(10).precio(), EntradaVip(10, 'zumo').precio())"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Comprueba que una entrada VIP es una entrada
python3 -c "from entradas import Entrada, EntradaVip; v = EntradaVip(10, 'zumo'); print(isinstance(v, Entrada), v.bebida)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente cree que se hereda siempre que se quiere reutilizar código. No es así. Hereda solo si la subclase es un tipo de la superclase. Una entrada no es una cartera, aunque las dos tengan un precio. Si la relación es «tiene un», se usa otra técnica, la composición.
Polimorfismo: la misma llamada, un resultado propio
La taquilla suma entradas sin saber de qué tipo es cada una. Para cada objeto llama a precio(). Cada objeto calcula el suyo.
Esto es el polimorfismo. Si mañana el cine crea una entrada para jubilados, la taquilla no cambia ni una línea.
Escribe la taquilla que suma entradas
printf 'from entradas import Entrada, EntradaEstudiante, EntradaVip\n\n\ndef total(entradas):\n suma = 0\n for entrada in entradas:\n suma = suma + entrada.precio()\n return suma\n\n\nprint(total([Entrada(10), EntradaEstudiante(10), EntradaVip(10, "zumo")]))\n' > taquilla.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta la taquilla
python3 taquilla.pySe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.