Clases y Objetos en Python
🗺️ Mapa de la Lección
⏱ 2 horas🟡 Intermedio🎯 Qué aprenderás
- Entender conceptos de POO: clases, objetos, métodos, atributos
- Crear clases y objetos en Python
- Usar __init__ para inicializar objetos
- Entender herencia y polimorfismo
- Aplicar encapsulación con métodos privados
🌍 Para qué te sirve
- Modelar entidades del mundo real: Usuario, Producto, Carrito
- APIs y frameworks: Django, Flask usan clases extensivamente
- Sistemas complejos: organizar código con relaciones entre objetos
- Reutilización: crear plantillas (clases) para múltiples instancias
- Abstracción: ocultar complejidad detrás de interfaces simples
- Mantenimiento: cambios en una clase afectan todas sus instancias
🎯 ¿Por qué aprender POO?
Hasta ahora has usado funciones y estructuras de datos por separado. Pero imagina que trabajas con usuarios: cada usuario tiene nombre, email, edad, y puede hacer cosas como "iniciar sesión" o "actualizar perfil".
La POO te permite:
- Agrupar datos y comportamientos relacionados
- Crear múltiples instancias similares fácilmente
- Organizar código de forma más clara y escalable
- Modelar entidades del mundo real de forma natural
- Reutilizar código mediante herencia
Sin POO, tendrías variables sueltas y funciones que reciben esos datos, lo cual se vuelve difícil de mantener cuando el código crece.
🌍 Casos reales donde se usa
La POO está en prácticamente todos los frameworks y proyectos grandes:
- APIs y frameworks: Django, Flask usan clases extensivamente
- Modelar entidades: Usuario, Producto, Carrito, Orden
- Sistemas complejos: Organizar código con relaciones entre objetos
- Reutilización: Crear plantillas (clases) para múltiples instancias
- Abstracción: Ocultar complejidad detrás de interfaces simples
- Mantenimiento: Cambios en una clase afectan todas sus instancias
Ejemplo real: En Django, cada modelo es una clase que representa una tabla de base de datos. class Usuario(models.Model) define la estructura y comportamiento de los usuarios.
💡 Concepto base
La Programación Orientada a Objetos (POO) agrupa datos (atributos) y comportamientos (métodos) relacionados en "clases". Una clase es como un molde que define cómo crear objetos.
Lo genial de Python: La sintaxis de POO es clara y permite herencia, polimorfismo y encapsulación de forma elegante.
# Definir una clase
class Usuario:
def __init__(self, nombre, email):
self.nombre = nombre
self.email = email
def iniciar_sesion(self):
return f"{self.nombre} ha iniciado sesión"
# Crear objetos (instancias)
usuario1 = Usuario("Ana", "ana@email.com")
print(usuario1.iniciar_sesion())
Ana ha iniciado sesión
Una clase es como la receta estándar de chilaquiles al pastor. Define qué ingredientes necesita (atributos) y qué pasos seguir (métodos). Un objeto es como un plato real de chilaquiles que preparas siguiendo esa receta. Puedes crear muchos objetos (muchos platos) usando la misma clase (la misma receta), pero cada uno puede tener sus propias variaciones (diferentes niveles de picante, más o menos queso, etc.). La receta (clase) es la plantilla, cada plato (objeto) es una instancia única.
Antes de continuar: Asegúrate de entender Funciones y Diccionarios y Sets.
Conceptos clave:
- Clase = Plano o molde (la receta)
- Objeto = Instancia real (el plato preparado)
- Atributos = Datos del objeto (ingredientes)
- Métodos = Comportamientos del objeto (pasos de la receta)
Objeto = Instancia real
- Es la "cosa" creada a partir de la clase
- Ejemplo:
usuario1 = Usuario("Ana", "ana@email.com", 25)crea un objeto usuario real - Puedes crear muchos objetos de la misma clase
Atributos = Datos del objeto
- Son las variables que guardan información del objeto
- Ejemplo:
self.nombre,self.email,self.edad - Cada objeto tiene sus propios valores
Métodos = Acciones del objeto
- Son funciones que el objeto puede ejecutar
- Ejemplo:
def iniciar_sesion(self):- el usuario puede iniciar sesión - Usan
selfpara acceder a los atributos del objeto
Analogía real:
- Clase
Coche= el diseño de un coche (tiene ruedas, motor, puede acelerar) - Objeto
mi_coche= tu coche específico (rojo, marca Toyota, con 50000 km) - Atributos = color, marca, kilometraje
- Métodos = acelerar(), frenar(), encender()
Crear una Clase Básica
Sintaxis básica
class NombreClase:
def __init__(self, parametros):
# Constructor: inicializa el objeto
self.atributo = valor
def metodo(self):
# Comportamiento
pass
Ejemplo práctico completo
Vamos a crear una clase Persona que tenga datos (nombre, edad, energía) y comportamientos (saludar, trabajar):
class Persona:
def __init__(self, nombre, edad):
# __init__ es el constructor - se ejecuta al crear el objeto
self.nombre = nombre # Atributo: guarda el nombre
self.edad = edad # Atributo: guarda la edad
self.energia = 100 # Atributo: todos empiezan con 100 de energía
def saludar(self):
# Método: acción que puede hacer la persona
print(f"Hola, soy {self.nombre}")
def trabajar(self):
# Método: otra acción, pero con lógica condicional
if self.energia > 20:
self.energia -= 20 # Gasta energía
print(f"{self.nombre} está trabajando...")
else:
print(f"{self.nombre} está demasiado cansado para trabajar")
# Crear objetos (Instanciación)
# Cada objeto es independiente - tienen sus propios valores
persona1 = Persona("Ana", 28)
persona2 = Persona("Carlos", 35)
# Usar los objetos - llamar sus métodos
persona1.saludar() # "Hola, soy Ana"
persona2.trabajar() # "Carlos está trabajando..."
print(f"Energía de {persona2.nombre}: {persona2.energia}") # 80 (100 - 20)
¿Qué está pasando aquí?
__init__se ejecuta automáticamente cuando creas un objetoselfse refiere al objeto actual (persona1 o persona2)- Cada objeto mantiene sus propios valores (Ana tiene 28 años, Carlos tiene 35)
- Los métodos pueden modificar los atributos del objeto (
self.energia -= 20)
Prueba esto: Crea persona3 y haz que trabaje 6 veces. ¿Qué pasa con su energía?
Atributos de Clase vs Instancia
Atributos de instancia
Son específicos de cada objeto. Se definen dentro de __init__ usando self.
class Empleado:
def __init__(self, nombre, id_empleado):
self.nombre = nombre # Único para cada empleado
self.id = id_empleado # Único para cada empleado
e1 = Empleado("Luis", 101)
e2 = Empleado("Marta", 102)
Atributos de clase
Son compartidos por todas las instancias de la clase. Se definen directamente en la clase.
class Empleado:
empresa = "TechCorp Inc." # Compartido por todos
def __init__(self, nombre):
self.nombre = nombre
e1 = Empleado("Luis")
e2 = Empleado("Marta")
print(e1.empresa) # TechCorp Inc.
print(e2.empresa) # TechCorp Inc.
Tipos de Métodos
Métodos de instancia
Reciben self como primer parámetro. Actúan sobre una instancia específica.
def saludar(self):
print(f"Hola, soy {self.nombre}")
Métodos de clase
Reciben cls como primer parámetro. Actúan sobre la clase, no sobre una instancia. Usan el decorador @classmethod.
class Empleado:
contador = 0
def __init__(self):
Empleado.contador += 1
@classmethod
def total_empleados(cls):
return cls.contador
Métodos estáticos
No reciben ni self ni cls. Son funciones normales que pertenecen lógicamente a la clase.
@staticmethod
def es_dia_laboral(dia):
return dia.lower() not in ["sábado", "domingo"]
Herencia
La herencia permite crear nuevas clases basadas en clases existentes, reutilizando y extendiendo su código.
# Clase Padre (Superclase)
class Vehiculo:
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo
def arrancar(self):
print("El vehículo está arrancando")
# Clase Hija (Subclase)
class Coche(Vehiculo):
def __init__(self, marca, modelo, puertas):
super().__init__(marca, modelo) # Llamar constructor del padre
self.puertas = puertas
def tocar_bocina(self):
print("¡Bip bip!")
# Uso
mi_coche = Coche("Toyota", "Corolla", 4)
mi_coche.arrancar() # Heredado
mi_coche.tocar_bocina() # Propio
Encapsulación
Proteger los datos internos de un objeto para que no sean modificados incorrectamente desde fuera.
- Público:
self.nombre(Accesible desde cualquier lugar) - Protegido:
self._nombre(Convención: no tocar desde fuera) - Privado:
self.__nombre(Python lo oculta, difícil acceso desde fuera)
class CuentaBancaria:
def __init__(self, titular, saldo):
self.titular = titular
self.__saldo = saldo # Privado
def depositar(self, monto):
if monto > 0:
self.__saldo += monto
def ver_saldo(self):
return self.__saldo
cuenta = CuentaBancaria("Juan", 1000)
# cuenta.__saldo = 5000 # Esto daría error o no afectaría la variable real interna
cuenta.depositar(500)
print(cuenta.ver_saldo())
Polimorfismo
Capacidad de objetos de diferentes clases de responder al mismo método de manera distinta.
class Perro:
def hablar(self):
print("Guau!")
class Gato:
def hablar(self):
print("Miau!")
animales = [Perro(), Gato()]
for animal in animales:
animal.hablar() # Cada uno responde a su manera
Ejercicios Prácticos
Ejercicio 1: Sistema de Gestión de Biblioteca
class Libro:
def __init__(self, titulo, autor, isbn):
self.titulo = titulo
self.autor = autor
self.isbn = isbn
self.disponible = True
def prestar(self):
if self.disponible:
self.disponible = False
return True
return False
def devolver(self):
self.disponible = True
class Biblioteca:
def __init__(self):
self.libros = []
def agregar_libro(self, libro):
self.libros.append(libro)
print(f"Libro agregado: {libro.titulo}")
def buscar_por_titulo(self, titulo):
for libro in self.libros:
if titulo.lower() in libro.titulo.lower():
return libro
return None
# Uso
biblio = Biblioteca()
l1 = Libro("Python 101", "Guido van Rossum", "12345")
l2 = Libro("Clean Code", "Robert Martin", "67890")
biblio.agregar_libro(l1)
biblio.agregar_libro(l2)
libro = biblio.buscar_por_titulo("python")
if libro and libro.prestar():
print(f"Te has llevado: {libro.titulo}")
else:
print("Libro no disponible o no encontrado")
Buenas Prácticas
- Clases sustantivos, Métodos verbos:
class Usuarioydef guardar(). - Principio de Responsabilidad Única: Una clase debe encargarse de una sola cosa.
- Documentación: Usa docstrings para explicar qué hace la clase y sus métodos.
Errores Comunes
- Olvidar
self: En Python es obligatorio ponerselfcomo primer parámetro en métodos de instancia. - No inicializar el padre: Al usar herencia, si defines
__init__en la hija, recuerda llamar asuper().__init__.
Recursos Adicionales
2. Documentación
class Calculadora:
"""Clase para realizar operaciones matemáticas básicas"""
def __init__(self, marca):
"""
Inicializa la calculadora
Args:
marca (str): Marca de la calculadora
"""
self.marca = marca
def sumar(self, a, b):
"""
Suma dos números
Args:
a (float): Primer número
b (float): Segundo número
Returns:
float: Resultado de la suma
"""
return a + b
3. Encapsulación apropiada
class CuentaBancaria:
def __init__(self, titular, saldo_inicial):
self.titular = titular # Público
self._saldo = saldo_inicial # Protegido
self.__numero_cuenta = self._generar_numero() # Privado
def _generar_numero(self):
"""Método protegido para generar número de cuenta"""
import random
return f"ACC{random.randint(100000, 999999)}"
def obtener_saldo(self):
"""Método público para obtener saldo"""
return self._saldo
Errores Comunes
1. Olvidar self en métodos
# ❌ Malo
class Persona:
def __init__(self, nombre):
self.nombre = nombre
def saludar():
print(f"Hola, soy {self.nombre}") # Error: falta self
# ✅ Bueno
class Persona:
def __init__(self, nombre):
self.nombre = nombre
def saludar(self):
print(f"Hola, soy {self.nombre}")
2. No llamar super().init()
# ❌ Malo
class Hijo(Padre):
def __init__(self, nombre, edad):
self.nombre = nombre # No inicializa atributos del padre
self.edad = edad
# ✅ Bueno
class Hijo(Padre):
def __init__(self, nombre, edad):
super().__init__(nombre) # Inicializa atributos del padre
self.edad = edad
3. Modificar atributos de clase incorrectamente
# ❌ Malo
class Persona:
contador = 0
def __init__(self, nombre):
self.nombre = nombre
self.contador += 1 # Modifica instancia, no clase
# ✅ Bueno
class Persona:
contador = 0
def __init__(self, nombre):
self.nombre = nombre
Persona.contador += 1 # Modifica la clase
Recursos Adicionales
Recursos Adicionales
Documentación Oficial
- Documentación oficial de Python sobre clases
- Tutorial de POO en Python
- PEP 8 - Guía de estilo para código Python
- PEP 3115 - Metaclasses
Bibliografía Recomendada
- Fluent Python (Luciano Ramalho) - Capítulos 1, 9-12: Data Model y POO
- Effective Python (Brett Slatkin) - Items sobre clases y objetos
- Python Tricks (Dan Bader) - Capítulo sobre POO en Python
- Python Cookbook, 3rd Ed (Beazley & Jones) - Recetas sobre clases y objetos
- Clean Code (Robert C. Martin) - Capítulos sobre POO y diseño de clases
- Design Patterns: Elements of Reusable OOP (Gang of Four) - Patrones de diseño clásicos
Conceptos Relacionados
- Dataclasses - Forma moderna de crear clases
- Decoradores - Extiende clases y métodos
- Módulos y Paquetes - Organiza clases en módulos
Siguiente paso
Ahora que entiendes las clases básicas, aprende sobre dataclasses, una forma moderna y concisa de crear clases. Continúa con: Dataclasses