Introducción
Contenido de la lección.
Objetivos de aprendizaje
- Objetivo 1
- Objetivo 2
- Objetivo 3
Objetivos de Aprendizaje
Al finalizar este tema, serás capaz de:
- Comprender los conceptos fundamentales de la Programación Orientada a Objetos
- Aprender a definir clases y crear objetos en Python
- Dominar la sintaxis para atributos de instancia y métodos de clase
- Implementar casos de uso reales usando clases y objetos
- Aplicar principios de encapsulación básica en el diseño de clases
📚 Conceptos Fundamentales de POO
La Programación Orientada a Objetos se basa en cuatro pilares fundamentales: encapsulación, herencia, polimorfismo y abstracción. En este tema nos enfocaremos en los elementos básicos: clases y objetos. Una CLASE es un molde o plantilla que define las características y comportamientos que tendrán los objetos. Un OBJETO es una instancia específica de una clase, con valores particulares para sus atributos. Los ATRIBUTOS son las características o propiedades que describe un objeto (como color, tamaño, nombre). Los MÉTODOS son las funciones que definen los comportamientos o acciones que puede realizar un objeto. La POO nos permite organizar el código de manera modular, reutilizable y más cercana a como pensamos naturalmente sobre los problemas del mundo real.
# Definición básica de una clase
class Persona:
pass # Clase vacía por ahora
# Crear un objeto (instancia) de la clase
persona1 = Persona()
print(type(persona1))
print(persona1)
<__main__.Persona object at 0x...>
🎯 Definición de Clases con Atributos
Los atributos son variables que pertenecen a una clase y almacenan datos específicos de cada objeto. En Python, los atributos se pueden definir de varias maneras. Los atributos de instancia son únicos para cada objeto y se definen típicamente en el método especial __init__, que es el constructor de la clase. Este método se ejecuta automáticamente cuando se crea un nuevo objeto. Los atributos de clase son compartidos por todas las instancias de la clase. Es importante entender la diferencia entre estos tipos de atributos para diseñar clases efectivas. El método __init__ recibe como primer parámetro 'self', que es una referencia al objeto que se está creando, permitiendo acceder y modificar sus atributos específicos.
class Estudiante:
# Atributo de clase (compartido por todas las instancias)
universidad = 'Universidad Técnica'
def __init__(self, nombre, edad, carrera):
# Atributos de instancia (únicos para cada objeto)
self.nombre = nombre
self.edad = edad
self.carrera = carrera
# Crear objetos con diferentes valores
estudiante1 = Estudiante('Ana', 20, 'Ingeniería de Sistemas')
estudiante2 = Estudiante('Carlos', 22, 'Ingeniería Civil')
print(f'Estudiante 1: {estudiante1.nombre}, {estudiante1.edad} años')
print(f'Carrera: {estudiante1.carrera}')
print(f'Universidad: {estudiante1.universidad}')
print(f'Estudiante 2: {estudiante2.nombre}, {estudiante2.edad} años')
Estudiante 1: Ana, 20 años Carrera: Ingeniería de Sistemas Universidad: Universidad Técnica Estudiante 2: Carlos, 22 años
💡 Métodos de Instancia
Los métodos son funciones definidas dentro de una clase que determinan el comportamiento de los objetos. Los métodos de instancia son los más comunes y siempre reciben 'self' como primer parámetro, lo que les permite acceder y modificar los atributos del objeto. Los métodos pueden recibir parámetros adicionales y retornar valores, al igual que las funciones normales. Es una buena práctica crear métodos para acceder y modificar atributos (getters y setters), realizar cálculos basados en los atributos del objeto, o ejecutar acciones específicas relacionadas con el objeto. Los métodos encapsulan la lógica relacionada con los datos, manteniendo la cohesión del código y facilitando el mantenimiento.
class CuentaBancaria:
def __init__(self, titular, saldo_inicial=0):
self.titular = titular
self.saldo = saldo_inicial
self.historial = []
def depositar(self, cantidad):
if cantidad > 0:
self.saldo += cantidad
self.historial.append(f'Depósito: +${cantidad}')
return True
return False
def retirar(self, cantidad):
if cantidad > 0 and cantidad <= self.saldo:
self.saldo -= cantidad
self.historial.append(f'Retiro: -${cantidad}')
return True
return False
def consultar_saldo(self):
return f'Saldo actual: ${self.saldo}'
def mostrar_historial(self):
for transaccion in self.historial:
print(transaccion)
# Uso de la clase
cuenta = CuentaBancaria('María García', 1000)
print(cuenta.consultar_saldo())
cuenta.depositar(500)
cuenta.retirar(200)
print(cuenta.consultar_saldo())
cuenta.mostrar_historial()
Saldo actual: $1000 Saldo actual: $1300 Depósito: +$500 Retiro: -$200
🔧 Múltiples Instancias y Comportamiento Independiente
Una de las ventajas principales de la POO es la capacidad de crear múltiples objetos independientes a partir de la misma clase. Cada objeto mantiene su propio estado y puede ser manipulado de forma independiente. Esto es fundamental para modelar sistemas complejos donde necesitamos múltiples entidades similares pero con características distintas. Los objetos pueden interactuar entre sí através de métodos, lo que permite crear sistemas dinámicos y realistas. Es importante entender que aunque los objetos comparten la misma estructura (definida por la clase), cada uno mantiene sus propios valores de atributos y puede evolucionar de manera independiente durante la ejecución del programa.
class Vehiculo:
def __init__(self, marca, modelo, kilometraje=0):
self.marca = marca
self.modelo = modelo
self.kilometraje = kilometraje
self.encendido = False
def encender(self):
if not self.encendido:
self.encendido = True
return f'{self.marca} {self.modelo} encendido'
return f'{self.marca} {self.modelo} ya está encendido'
def conducir(self, distancia):
if self.encendido:
self.kilometraje += distancia
return f'Conducido {distancia} km. Total: {self.kilometraje} km'
return 'Debe encender el vehículo primero'
def apagar(self):
self.encendido = False
return f'{self.marca} {self.modelo} apagado'
# Crear varios vehículos independientes
auto1 = Vehiculo('Toyota', 'Corolla')
auto2 = Vehiculo('Honda', 'Civic', 15000)
moto1 = Vehiculo('Yamaha', 'MT-07')
# Operar cada vehículo independientemente
print(auto1.encender())
print(auto1.conducir(50))
print(auto2.encender())
print(auto2.conducir(100))
print(f'Auto1 kilometraje: {auto1.kilometraje}')
print(f'Auto2 kilometraje: {auto2.kilometraje}')
Toyota Corolla encendido Conducido 50 km. Total: 50 km Honda Civic encendido Conducido 100 km. Total: 15100 km Auto1 kilometraje: 50 Auto2 kilometraje: 15100
⚡ Casos de Uso Avanzados y Aplicaciones Profesionales
En el desarrollo profesional, las clases y objetos son fundamentales para crear sistemas escalables y mantenibles. Algunos casos de uso comunes incluyen: modelado de entidades de negocio (usuarios, productos, pedidos), implementación de estructuras de datos personalizadas, creación de APIs y servicios web, desarrollo de juegos y simulaciones, y sistemas de gestión de recursos. Las clases permiten encapsular lógica compleja y crear abstracciones que facilitan el trabajo en equipo. En aplicaciones empresariales, es común tener clases que representen conceptos del dominio del negocio, lo que facilita la comunicación entre desarrolladores y stakeholders. La capacidad de crear múltiples instancias permite manejar grandes volúmenes de datos de manera eficiente y organizada.
class Empleado:
contador_empleados = 0
def __init__(self, nombre, departamento, salario):
Empleado.contador_empleados += 1
self.id_empleado = Empleado.contador_empleados
self.nombre = nombre
self.departamento = departamento
self.salario = salario
self.activo = True
def aumentar_salario(self, porcentaje):
aumento = self.salario * (porcentaje / 100)
self.salario += aumento
return f'Salario aumentado en {porcentaje}%. Nuevo salario: ${self.salario:.2f}'
def transferir_departamento(self, nuevo_departamento):
depto_anterior = self.departamento
self.departamento = nuevo_departamento
return f'{self.nombre} transferido de {depto_anterior} a {nuevo_departamento}'
def obtener_info(self):
estado = 'Activo' if self.activo else 'Inactivo'
return f'ID: {self.id_empleado} | {self.nombre} | {self.departamento} | ${self.salario} | {estado}'
# Sistema de gestión
emp1 = Empleado('Juan Pérez', 'Desarrollo', 3000)
emp2 = Empleado('Laura Rodríguez', 'Marketing', 2800)
emp3 = Empleado('Carlos López', 'Ventas', 3200)
print('=== SISTEMA DE EMPLEADOS ===')
print(emp1.obtener_info())
print(emp2.obtener_info())
print(emp3.obtener_info())
print(f'Total empleados: {Empleado.contador_empleados}')
print('\n=== OPERACIONES ===')
print(emp1.aumentar_salario(10))
print(emp2.transferir_departamento('Desarrollo'))
=== SISTEMA DE EMPLEADOS === ID: 1 | Juan Pérez | Desarrollo | $3000 | Activo ID: 2 | Laura Rodríguez | Marketing | $2800 | Activo ID: 3 | Carlos López | Ventas | $3200 | Activo Total empleados: 3 === OPERACIONES === Salario aumentado en 10%. Nuevo salario: $3300.00 Laura Rodríguez transferido de Marketing a Desarrollo
Ejercicios Prácticos
Crear una Clase Libro
BÁSICODescripción:
Define una clase Libro con atributos titulo, autor, paginas y disponible (booleano). Implementa métodos para prestar el libro, devolverlo y mostrar información. Crea al menos 3 libros diferentes y simula operaciones de préstamo.
Sistema de Productos de Tienda
INTERMEDIODescripción:
Crea una clase Producto con nombre, precio, stock y código. Implementa métodos para agregar stock, vender productos (reducir stock), aplicar descuentos y calcular valor total del inventario. Crea un inventario con 5 productos diferentes.
Simulador de Cuentas Bancarias Avanzado
AVANZADODescripción:
Extiende el ejemplo de CuentaBancaria agregando tipos de cuenta (ahorros, corriente), límites de retiro, intereses mensuales y la capacidad de transferir dinero entre cuentas. Simula un mes de operaciones bancarias.
Registro de Estudiantes Universitarios
INTERMEDIODescripción:
Diseña una clase EstudianteUniversitario con carnet, nombre, carrera, semestre, materias inscritas y calificaciones. Implementa métodos para inscribir materias, registrar calificaciones, calcular promedio y determinar estado académico.
Resumen y Próximos Pasos
En esta introducción a POO hemos establecido los fundamentos esenciales: clases como plantillas, objetos como instancias, atributos para almacenar datos y métodos para definir comportamientos. Estos conceptos forman la base sobre la cual construiremos conocimientos más avanzados como herencia, polimorfismo y encapsulación. La práctica con múltiples ejemplos y ejercicios consolida la comprensión de cómo modelar problemas reales usando POO. En el próximo tema exploraremos métodos especiales y propiedades avanzadas que nos permitirán crear clases más sofisticadas y funcionales, acercándonos cada vez más a aplicaciones profesionales complejas.