Programación Orientada a Objetos (POO)

Clases y objetos

En Python, las clases y los objetos son los principales conceptos de la programación orientada a objetos (POO). Una clase es un modelo para crear objetos (una forma de empaquetar datos y funcionalidad juntos). Un objeto es una instancia de una clase.

Código de Ejemplo

				
					# Definición de una clase
class Persona:
    # Método constructor
    def __init__(self, nombre, edad):
        self.nombre = nombre  # Atributo de instancia
        self.edad = edad  # Atributo de instancia

    # Método de instancia
    def saludar(self):
        print(f"Hola, me llamo {self.nombre} y tengo {self.edad} años.")

    # Método para cambiar el nombre
    def cambiar_nombre(self, nuevo_nombre):
        self.nombre = nuevo_nombre

# Crear objetos (instancias de la clase)
persona1 = Persona("Juan", 30)
persona2 = Persona("Ana", 25)

# Acceder a atributos y métodos
persona1.saludar()  # Output: Hola, me llamo Juan y tengo 30 años.
persona2.saludar()  # Output: Hola, me llamo Ana y tengo 25 años.

# Cambiar el nombre de una persona
persona1.cambiar_nombre("Carlos")
persona1.saludar()  # Output: Hola, me llamo Carlos y tengo 30 años.

# Atributo de clase
class PersonaConAtributoClase:
    especie = "Humano"  # Atributo de clase

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

# Acceso a atributo de clase
print(PersonaConAtributoClase.especie)  # Output: Humano
persona3 = PersonaConAtributoClase("Luis", 40)
print(persona3.especie)  # Output: Humano

# Método de clase
class PersonaConMetodoClase:
    especie = "Humano"

    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

    @classmethod
    def crear_desde_nacimiento(cls, nombre, anio_nacimiento):
        edad = 2023 - anio_nacimiento
        return cls(nombre, edad)

# Crear objeto utilizando método de clase
persona4 = PersonaConMetodoClase.crear_desde_nacimiento("Elena", 1990)
print(persona4.nombre, persona4.edad)  # Output: Elena 33

# Método estático
class Matematica:
    @staticmethod
    def sumar(a, b):
        return a + b

# Uso de método estático
resultado = Matematica.sumar(5, 3)
print("Resultado de la suma:", resultado)  # Output: Resultado de la suma: 8

				
			

Explicación

Definición de una Clase

Una clase en Python se define utilizando la palabra clave class seguida del nombre de la clase y dos puntos. Dentro de la clase, se pueden definir atributos y métodos.

  • Atributos: Variables que pertenecen a una clase o a una instancia de una clase.
  • Métodos: Funciones que pertenecen a una clase.

Método Constructor

El método __init__ es un método especial conocido como constructor. Se ejecuta automáticamente cuando se crea un nuevo objeto de la clase. Este método se utiliza para inicializar los atributos del objeto.

  • self: Es una referencia a la instancia actual de la clase y se utiliza para acceder a los atributos y métodos del objeto.

Crear Objetos

Para crear un objeto de una clase, se llama a la clase como si fuera una función, pasando los argumentos necesarios al constructor.

  • persona1 = Persona("Juan", 30): Crea una nueva instancia de la clase Persona con los atributos nombre y edad.

Acceder a Atributos y Métodos

Los atributos y métodos de un objeto se acceden utilizando la notación de punto.

  • persona1.nombre: Accede al atributo nombre del objeto persona1.
  • persona1.saludar(): Llama al método saludar del objeto persona1.

Métodos de Clase y Métodos Estáticos

  • Métodos de Clase: Se definen utilizando el decorador @classmethod. Reciben la clase como primer argumento (cls). Se utilizan para crear métodos que afecten a la clase en lugar de a las instancias de la clase.

    En el ejemplo, el método de clase crear_desde_nacimiento crea una nueva instancia de PersonaConMetodoClase calculando la edad a partir del año de nacimiento.

  • Métodos Estáticos: Se definen utilizando el decorador @staticmethod. No reciben implícitamente una referencia a self o cls. Se utilizan para definir funciones que están relacionadas con la clase, pero no dependen de ninguna instancia de la clase.

    En el ejemplo, el método estático sumar realiza una suma de dos números y no depende de ninguna instancia de la clase Matematica.

Atributos de Clase

Los atributos de clase son compartidos por todas las instancias de la clase. Se definen dentro del cuerpo de la clase pero fuera de cualquier método.

  • especie = "Humano": Define un atributo de clase que es compartido por todas las instancias de PersonaConAtributoClase.

Resumen

  • Clases y Objetos: Una clase es un modelo para crear objetos. Un objeto es una instancia de una clase.
  • Método Constructor (__init__): Inicializa los atributos de una nueva instancia de la clase.
  • Atributos: Variables que pertenecen a una clase o a una instancia de una clase.
  • Métodos: Funciones que pertenecen a una clase y se utilizan para definir el comportamiento de los objetos.
  • Métodos de Clase (@classmethod): Métodos que afectan a la clase en lugar de a las instancias de la clase.
  • Métodos Estáticos (@staticmethod): Funciones relacionadas con la clase que no dependen de ninguna instancia de la clase.
  • Atributos de Clase: Atributos compartidos por todas las instancias de una clase.

Principios de POO

La Programación Orientada a Objetos (POO) es un paradigma de programación que utiliza «objetos» para modelar datos y comportamiento. Los cuatro principios fundamentales de la POO son: Encapsulamiento, Herencia, Polimorfismo y Abstracción.

Código de Ejemplo

				
					# Encapsulamiento
class Persona:
    def __init__(self, nombre, edad):
        self.nombre = nombre  # Público
        self.__edad = edad  # Privado

    def obtener_edad(self):
        return self.__edad

    def establecer_edad(self, edad):
        if edad > 0:
            self.__edad = edad

# Herencia
class Empleado(Persona):
    def __init__(self, nombre, edad, salario):
        super().__init__(nombre, edad)
        self.salario = salario

    def mostrar_informacion(self):
        print(f"Nombre: {self.nombre}, Edad: {self.obtener_edad()}, Salario: {self.salario}")

# Polimorfismo
class Animal:
    def hacer_sonido(self):
        raise NotImplementedError("Este método debe ser implementado por la subclase")

class Perro(Animal):
    def hacer_sonido(self):
        return "Guau"

class Gato(Animal):
    def hacer_sonido(self):
        return "Miau"

# Abstracción
from abc import ABC, abstractmethod

class FiguraGeometrica(ABC):
    @abstractmethod
    def area(self):
        pass

class Circulo(FiguraGeometrica):
    def __init__(self, radio):
        self.radio = radio

    def area(self):
        return 3.14159 * (self.radio ** 2)

class Rectangulo(FiguraGeometrica):
    def __init__(self, ancho, alto):
        self.ancho = ancho
        self.alto = alto

    def area(self):
        return self.ancho * self.alto

# Uso de clases
# Encapsulamiento
persona = Persona("Juan", 30)
print(persona.nombre)
print(persona.obtener_edad())
persona.establecer_edad(31)
print(persona.obtener_edad())

# Herencia
empleado = Empleado("Ana", 25, 50000)
empleado.mostrar_informacion()

# Polimorfismo
animales = [Perro(), Gato()]
for animal in animales:
    print(animal.hacer_sonido())

# Abstracción
figuras = [Circulo(5), Rectangulo(4, 6)]
for figura in figuras:
    print(figura.area())

				
			

Explicación

Encapsulamiento

El encapsulamiento es el principio que permite ocultar los detalles internos de un objeto y exponer solo lo necesario. En Python, los atributos y métodos privados se definen utilizando dos guiones bajos (__) antes del nombre.

En el ejemplo, la clase Persona tiene un atributo privado __edad y métodos públicos obtener_edad y establecer_edad para acceder y modificar ese atributo de manera controlada.

Herencia

La herencia permite que una clase derive de otra, heredando sus atributos y métodos. La clase derivada puede añadir nuevas funcionalidades o modificar las existentes.

En el ejemplo, la clase Empleado hereda de Persona y añade el atributo salario y el método mostrar_informacion.

Polimorfismo

El polimorfismo permite que diferentes clases sean tratadas como una misma interfaz a través de métodos comunes. Esencialmente, permite que una operación se comporte de diferentes maneras en diferentes instancias de clases.

En el ejemplo, las clases Perro y Gato heredan de Animal y sobrescriben el método hacer_sonido. Ambas pueden ser tratadas como instancias de Animal y llamar a su método hacer_sonido.

Abstracción

La abstracción es el principio que permite definir interfaces abstractas y clases abstractas que no pueden ser instanciadas directamente. Se utilizan para definir métodos que deben ser implementados por las subclases.

En el ejemplo, FiguraGeometrica es una clase abstracta con un método abstracto area. Las clases Circulo y Rectangulo implementan el método area.

Resumen

  • Encapsulamiento: Oculta los detalles internos de un objeto y expone solo lo necesario.
  • Herencia: Permite que una clase derive de otra, heredando sus atributos y métodos.
  • Polimorfismo: Permite que diferentes clases sean tratadas como una misma interfaz a través de métodos comunes.
  • Abstracción: Permite definir interfaces y clases abstractas que no pueden ser instanciadas directamente.