Metodología de la programación estructurada: del análisis al código en Python
Objetivo: El alumno identificará los elementos del análisis, diseño y programación estructurados, y apreciará su importancia en el desarrollo de programas.
Tiempo de lectura: 8–10 minutos3.1 La programación estructurada
La programación estructurada es un paradigma que promueve escribir software claro, correcto y mantenible mediante:
- Control de flujo con tres estructuras básicas: secuencia, selección (if/elif/else) e iteración (while/for).
- Descomposición modular: dividir el problema en subproblemas (módulos) independientes y cohesionados.
- Refinamiento sucesivo: del panorama general al detalle, paso a paso.
- Diseño previo al código: seudocódigo, diagramas y tablas de decisión.
Ejemplo guía que usaremos
“Sistema de Gestión de Alumnos” (SGA) con operaciones para: alta, consulta, actualización, baja, cálculo de promedios y reporte de aprobación.
3.1.1 Definición del problema
Plantea el objetivo, las entradas, salidas, restricciones y casos de prueba. Una buena definición reduce riesgos de re-trabajo.
Objetivo: Administrar alumnos con sus calificaciones y asistencia para determinar si aprueban.
- Entradas: matrícula, nombre, lista de calificaciones, porcentaje de asistencia.
- Salidas: reportes, promedio por alumno, estado Aprobado/Reprobado.
- Restricciones: matrícula única; calificaciones 0–100; asistencia 0–100.
Datos de prueba iniciales:
- A001, “Ana”, [80, 90, 75], asistencia 92
- A002, “Luis”, [60, 70, 65], asistencia 78
3.1.2 Identificación de los módulos (subproblemas)
- Entrada y validación de datos
- Almacenamiento y búsqueda
- Cálculo de promedio
- Determinación de aprobación
- Actualización y eliminación
- Reporte
Nota de diseño: cada módulo será una función en Python. Evita efectos laterales innecesarios, y haz que cada función haga “una sola cosa bien”.
# Esqueleto de funciones (stubs)
def crear_alumno(db, matricula, nombre, calificaciones, asistencia): ...
def listar_alumnos(db): ...
def buscar_alumno(db, matricula): ...
def actualizar_alumno(db, matricula, **cambios): ...
def eliminar_alumno(db, matricula): ...
def calcular_promedio(calificaciones): ...
def esta_aprobado(promedio, asistencia): ...
3.1.3 Refinamiento sucesivo de los módulos
Refina cada módulo en pasos más simples hasta que el paso pueda traducirse directamente a código.
3.1.3.1 Seudocódigo y diagramas estructurados
INICIO SGA
MIENTRAS usuario no elija SALIR
mostrar_menu()
opcion ← leer_opcion()
SI opcion = ALTA ENTONCES
datos ← capturar_datos_alumno()
crear_alumno(db, datos)
SINO SI opcion = CONSULTA ENTONCES
listar_alumnos(db)
SINO SI opcion = ACTUALIZAR ENTONCES
matricula ← leer_matricula()
cambios ← capturar_cambios()
actualizar_alumno(db, matricula, cambios)
SINO SI opcion = BAJA ENTONCES
matricula ← leer_matricula()
eliminar_alumno(db, matricula)
SINO SI opcion = REPORTE ENTONCES
generar_reporte(db)
FIN SI
FIN MIENTRAS
FIN
3.1.3.2 El árbol y la tabla de decisiones
Árbol de módulos (resumen)
- Sistema de Gestión de Alumnos
- Entrada y validación
- Gestión de alumnos
- Alta
- Consulta
- Actualización
- Baja
- Cálculo de promedio
- Determinación de aprobación
- Reporte
Condición | Regla 1 | Regla 2 | Regla 3 | Regla 4 |
---|---|---|---|---|
Promedio ≥ 70 | Sí | No | No | Sí |
Asistencia ≥ 80 | Sí | Sí | No | No |
Acción: Estado | Aprobado | Reprobado | Reprobado | Reprobado |
3.2 Procedimientos recurrentes
Un procedimiento recurrente (recursivo) se define en términos de sí mismo. Útil para estructuras jerárquicas (árboles) o descomposición natural del problema.
Ejemplo 1: suma recursiva
def suma(lista):
# Caso base
if not lista:
return 0
# Caso recursivo
return lista[0] + suma(lista[1:])
print(suma([1, 2, 3, 4])) # 10
Ejemplo 2: imprimir árbol de módulos
arbol = {
"SGA": ["Entrada", {"Gestión": ["Alta", "Consulta", "Actualización", "Baja"]},
"Promedio", "Aprobación", "Reporte"]
}
def imprimir_arbol(nodo, nivel=0):
for k, hijos in nodo.items():
print(" " * nivel + "- " + k)
for h in hijos:
if isinstance(h, dict):
imprimir_arbol(h, nivel + 1)
else:
print(" " * (nivel + 1) + f"- {h}")
imprimir_arbol(arbol)
3.3 Uso de apuntadores
En Python no existen “apuntadores” como en C, pero las variables hacen referencia a objetos en memoria. Comprender referencias y mutabilidad evita errores sutiles.
Alias y mutabilidad
alfa = [1, 2, 3]
beta = alfa # beta referencia el mismo objeto
beta.append(4)
print(alfa) # [1, 2, 3, 4] ¡ambas referencias apuntan al mismo objeto!
Copias seguras
import copy
gamma = [1, [2, 3]]
shallow = gamma.copy() # copia superficial
deep = copy.deepcopy(gamma) # copia profunda
gamma[1].append(4)
print(shallow) # [1, [2, 3, 4]]
print(deep) # [1, [2, 3]]
3.4 Almacenamiento, actualización y eliminación de información en base a estructuras
Implementemos operaciones CRUD sobre una estructura en memoria. Usaremos un diccionario indexado por matrícula que almacena diccionarios por alumno.
Práctica guiada: mini-CRUD estructurado en Python
# Base de datos en memoria
alumnos = {} # {"A001": {"nombre": "...","calificaciones":[...], "asistencia": 0-100}}
def crear_alumno(db, matricula, nombre, calificaciones, asistencia):
if matricula in db:
raise ValueError("La matrícula ya existe.")
if not (0 <= asistencia <= 100):
raise ValueError("Asistencia fuera de rango.")
if not all(0 <= c <= 100 for c in calificaciones):
raise ValueError("Calificación fuera de rango.")
db[matricula] = {
"nombre": nombre.strip(),
"calificaciones": list(calificaciones),
"asistencia": float(asistencia)
}
def listar_alumnos(db):
for mat, datos in db.items():
prom = calcular_promedio(datos["calificaciones"])
estado = "Aprobado" if esta_aprobado(prom, datos["asistencia"]) else "Reprobado"
print(f"{mat} | {datos['nombre']:10s} | Prom: {prom:5.1f} | Asist: {datos['asistencia']:5.1f}% | {estado}")
def buscar_alumno(db, matricula):
return db.get(matricula)
def actualizar_alumno(db, matricula, **cambios):
if matricula not in db:
raise KeyError("No existe la matrícula.")
registro = db[matricula]
if "nombre" in cambios:
registro["nombre"] = cambios["nombre"].strip()
if "calificaciones" in cambios:
cal = cambios["calificaciones"]
if not all(0 <= c <= 100 for c in cal):
raise ValueError("Calificación fuera de rango.")
registro["calificaciones"] = list(cal)
if "asistencia" in cambios:
asist = float(cambios["asistencia"])
if not (0 <= asist <= 100):
raise ValueError("Asistencia fuera de rango.")
registro["asistencia"] = asist
def eliminar_alumno(db, matricula):
if matricula in db:
del db[matricula]
def calcular_promedio(calificaciones):
return sum(calificaciones)/len(calificaciones) if calificaciones else 0.0
def esta_aprobado(promedio, asistencia):
return promedio >= 70 and asistencia >= 80
# Demostración
if __name__ == "__main__":
crear_alumno(alumnos, "A001", "Ana", [80, 90, 75], 92)
crear_alumno(alumnos, "A002", "Luis", [60, 70, 65], 78)
actualizar_alumno(alumnos, "A002", calificaciones=[70, 80, 85], asistencia=82)
listar_alumnos(alumnos)
print("— Eliminando A001 —")
eliminar_alumno(alumnos, "A001")
listar_alumnos(alumnos)
Ejercicios propuestos
- Agrega validación para evitar listas vacías de calificaciones.
- Implementa función reporte_csv(db, ruta) que exporte los datos.
- Agrega un campo “grupo” y crea un reporte por grupo.
- Implementa confirmación de borrado (sí/no) antes de eliminar.
Buenas prácticas estructuradas
- Una función, una responsabilidad.
- Validación de entradas en los límites del módulo.
- Evita estados globales; pasa estructuras como parámetros.
- Pruebas con datos de borde (0, 100, listas vacías, duplicados).
Resumen
La programación estructurada proporciona un marco claro para pasar del análisis al diseño y de ahí al código. El uso de módulos, refinamiento sucesivo, seudocódigo, diagramas y tablas de decisión reduce la complejidad y mejora la mantenibilidad. En Python, comprender las referencias y las estructuras de datos te permitirá implementar CRUDs limpios y seguros.
Metodología de la programación estructurada