5: Programación Orientada a Objetos (POO)

5.1 ¿Qué es la Programación Orientada a Objetos?

La Programación Orientada a Objetos (POO) es un paradigma de programación que organiza el código alrededor de objetos en lugar de funciones y lógica. En la POO, todo se modela como un objeto, que representa una entidad del mundo real. Piensa en objetos como un Coche, un Perro o un Usuario.

Cada objeto tiene dos características principales:

  • Atributos: Las propiedades o características del objeto. (Ej. para un Coche: color, marca, velocidad).
  • Métodos: Las acciones que el objeto puede realizar. (Ej. para un Coche: acelerar(), frenar(), arrancar()).

La POO se basa en cuatro pilares:

  1. Herencia: Permite que una clase (hija) herede atributos y métodos de otra clase (padre).
  2. Polimorfismo: Permite que un mismo método se comporte de manera diferente en distintas clases.
  3. Encapsulamiento: Agrupa los datos y los métodos que los manipulan dentro de una misma unidad (la clase), y los protege de ser modificados externamente.
  4. Abstracción: Muestra solo los detalles relevantes del objeto al usuario, ocultando la complejidad interna.

5.2 Clases y Objetos

Una clase es como un "plano" o una plantilla para crear objetos. Es la definición de los atributos y métodos que tendrán los objetos que se creen a partir de ella. Un objeto es una instancia de una clase.

Definiendo una clase

Para definir una clase, usamos la palabra clave class. Los nombres de las clases suelen escribirse con la primera letra en mayúscula (CamelCase).

class Coche:
    # El método __init__ es el constructor
    def __init__(self, marca, color):
        self.marca = marca
        self.color = color

    # Un método de la clase
    def acelerar(self):
        print(f"El coche {self.marca} está acelerando.")

El método __init__ es especial; se le conoce como el constructor. Se ejecuta automáticamente cuando creas un nuevo objeto. El primer parámetro, self, es una referencia al objeto que se está creando. Los atributos definidos con self. (ej. self.marca) pertenecen al objeto.

Creando objetos (instancias)

Para crear un objeto a partir de la clase, simplemente llamas al nombre de la clase como si fuera una función.

# Crear dos objetos de la clase Coche
coche1 = Coche("Ford", "rojo")
coche2 = Coche("Tesla", "negro")

# Acceder a los atributos del objeto
print(coche1.color)  # Salida: rojo

# Llamar a un método del objeto
coche2.acelerar()    # Salida: El coche Tesla está acelerando.

5.3 Herencia y Polimorfismo

Herencia

La herencia nos permite crear una nueva clase (clase hija) que reutiliza los atributos y métodos de una clase existente (clase padre). Esto es útil para modelar relaciones del tipo "es un". Por ejemplo, un CocheElectrico es un tipo de Coche.

# Clase padre
class Vehiculo:
    def __init__(self, marca):
        self.marca = marca

    def describir(self):
        print(f"Este es un vehículo de la marca {self.marca}.")

# Clase hija que hereda de Vehiculo
class Coche(Vehiculo):
    def __init__(self, marca, color):
        # Llamar al constructor de la clase padre
        super().__init__(marca)
        self.color = color

    def describir(self):
        print(f"Este es un coche de la marca {self.marca} y color {self.color}.")

coche_tesla = Coche("Tesla", "gris")
coche_tesla.describir() # Salida: Este es un coche de la marca Tesla y color gris.

La función super() se usa para llamar a un método de la clase padre, en este caso, su constructor.

Polimorfismo

El polimorfismo significa que objetos de diferentes clases pueden responder a la misma llamada de método de manera distinta. En el ejemplo anterior, la clase hija Coche sobrescribe el método describir() de la clase padre Vehiculo para adaptarlo a su propia funcionalidad.

# Crear objetos de diferentes clases
vehiculo_generico = Vehiculo("Generico")
coche_tesla = Coche("Tesla", "gris")

vehiculo_generico.describir() # Salida: Este es un vehículo de la marca Generico.
coche_tesla.describir()       # Salida: Este es un coche de la marca Tesla y color gris.

Ambos objetos tienen un método describir(), pero el comportamiento es diferente para cada uno. ¡Esto es polimorfismo en acción!

La POO te proporciona un conjunto de herramientas poderosas para construir aplicaciones robustas y bien organizadas. En el siguiente módulo, exploraremos cómo organizar tu código en archivos y paquetes para proyectos más grandes.