Contenido del curso

Fundamentos de Programación y Python

Programación Orientada a Objetos en Python

Herencia en Python con clases de vehículos

Resumen

La herencia en Python te permite reutilizar código cuando varias clases comparten atributos y métodos comunes. Aquí verás cómo transformar un ejercicio de concesionaria en un modelo escalable usando una clase padre Vehiculo y subclases especializadas, ideal si estás aprendiendo programación orientada a objetos.

Cómo resolver el ejercicio inicial de la concesionaria?

Antes de aplicar herencia, conviene entender la solución base. El ejercicio plantea tres clases: Auto, Customer y Dealership, cada una con responsabilidades claras.

Qué hace la clase Auto y por qué usar getters?

La clase Auto arranca con cuatro atributos: marca, modelo, precio y un booleano is_available que define si el auto sigue en stock. Sus métodos permiten venderlo, consultar disponibilidad y devolver el precio.

El método get_price aparece desde el minuto [0:34] como ejemplo de getter, una convención para devolver el valor almacenado en un atributo sin exponerlo directamente. La lógica de venta valida primero la disponibilidad: si is_available es True, ejecuta la venta; si no, imprime que el auto no está disponible.

¿Qué es un getter en programación orientada a objetos? Es un método que devuelve el valor de un atributo de la clase. Por convención, su nombre empieza con get_ seguido del atributo, como get_price para retornar el precio.

Cómo se conectan Customer y Dealership con el inventario?

La clase Customer guarda un nombre y una colección de autos comprados. Cuando el cliente ejecuta una compra, el auto se añade a su colección si está disponible.

El Dealership gestiona dos listas: el inventario de autos y los compradores registrados. Sus métodos permiten:

  • Añadir autos al inventario.
  • Registrar clientes en la lista.
  • Mostrar qué autos siguen disponibles.

Al ejecutar el flujo con un Toyota Corolla, un Honda Civic y un Ford Mustang junto al cliente Carlos, el código confirma cada registro, muestra precios, procesa la compra del Corolla y luego rechaza un segundo intento sobre el mismo auto porque ya fue vendido.

Por qué aplicar herencia cuando crece el inventario?

A la concesionaria le va tan bien que ahora también vende bicicletas y camiones. Repetir atributos como marca, modelo y precio en tres clases distintas sería redundante. Aquí entra la herencia, el mecanismo que permite a varias clases hijas compartir atributos y métodos definidos en una superclase.

Cómo se construye la superclase Vehiculo?

La clase padre Vehiculo se crea con un constructor __init__ que recibe self, brand, model y price. Dentro inicializa esos atributos y añade is_available = True por defecto.

Luego incorpora métodos comunes a todos los vehículos:

  • sell: valida disponibilidad y marca el vehículo como vendido.
  • is_available: devuelve el estado actual.
  • get_price: retorna el precio almacenado.

Esta clase padre concentra todo lo que comparten autos, bicicletas y camiones, así no duplicas lógica.

Qué es NotImplementedError y cuándo usarlo?

Dentro de Vehiculo se definen también dos métodos especiales: start y stop. Pero como cada tipo de vehículo arranca y se detiene de forma distinta, la superclase no implementa la lógica. En su lugar, lanza una excepción NotImplementedError con el mensaje este método debe ser implementado por la subclase, según se ve en el minuto [6:45].

¿Qué hace NotImplementedError en Python? Es una excepción que obliga a las subclases a sobrescribir un método. Si una clase hija no lo implementa y se llama, Python lanza el error y detiene la ejecución.

Este patrón funciona como un contrato: cualquier subclase de Vehiculo está obligada a definir su propia versión de start y stop.

Cómo se crean las subclases que heredan de Vehiculo?

La sintaxis para declarar herencia en Python consiste en pasar la clase padre entre paréntesis al definir la clase hija. Por ejemplo:

python class Auto(Vehiculo): def start(self): if self.is_available: return f"El motor del coche {self.brand} está en marcha" return f"El coche {self.brand} no está disponible"

def stop(self): if self.is_available: return f"El motor del coche {self.brand} se ha detenido" return f"El coche {self.brand} no está disponible"

Fíjate que la subclase Auto no redefine atributos: hereda automáticamente brand, model, price e is_available de Vehiculo. Solo personaliza los métodos start y stop que estaban pendientes.

Qué ventajas concretas trae la herencia aquí?

Aplicar herencia en este caso te da varios beneficios medibles:

  1. Menos código duplicado: los cuatro atributos base se escriben una sola vez en la superclase.
  2. Mantenimiento más simple: si cambias la lógica de sell, se actualiza en todas las subclases automáticamente.
  3. Extensibilidad: añadir bicicletas o camiones solo requiere crear una nueva subclase y personalizar los métodos específicos.

La misma estructura se replicará después para las clases Bicicleta y Camion, cada una con su propia versión de cómo iniciar y detener su funcionamiento.

Si ya probaste el ejercicio, cuéntame en los comentarios cómo organizaste tus subclases y qué métodos decidiste personalizar.