Ya tienes las tres herramientas: sabes definir y llamar funciones (04-01), sabes darles parámetros y hacer que devuelvan valores (04-02), y sabes de qué deben depender para ser piezas autónomas (04-03). Lo que falta es el criterio: ante un programa de cien líneas escritas de un tirón, ¿por dónde se corta? ¿Cuántas funciones? ¿De qué tamaño? ¿Qué va dentro de cada una?
Esa pregunta no tiene una respuesta mecánica, pero sí tiene criterios sólidos y comprobables, y esta lección los recorre uno a uno. Al final los aplicaremos al caso que llevamos arrastrando desde el módulo 3: convertir el muro monolítico de tareafacil.py v0.6 en la versión 0.7, un programa organizado en funciones con un main() que se lee en veinte segundos. Lo que vamos a hacer tiene nombre propio: refactorizar, es decir, reorganizar el código sin cambiar lo que hace. Al terminar, TareaFácil se comportará exactamente igual de cara al usuario; lo que cambia es todo lo demás, la facilidad para entenderlo, corregirlo y ampliarlo.
Contenido
- Una función, una responsabilidad
- Tamaño y nivel de abstracción
- Diseño descendente: escribir el
main()primero - El árbol de llamadas
- Separar entrada/salida de lógica
- Nombres que describen el efecto
- DRY y el exceso contrario
- El bloque
if __name__ == "__main__": - TareaFácil v0.7: el refactor completo
- Errores comunes y consejos
- Ejercicios
- Conclusión
- Una función, una responsabilidad
El criterio principal es este: una función debe hacer una sola cosa y hacerla entera. La prueba práctica consiste en describirla en una frase corta, sin conjunciones. Si necesitas una «y», tienes dos funciones.
| Descripción de la función | Veredicto |
|---|---|
| «Pide un entero entre dos límites» | Una responsabilidad |
| «Pinta la ficha de una tarea» | Una responsabilidad |
| «Pide los datos y los guarda y avisa por pantalla» | Tres responsabilidades |
| «Valida el título y actualiza el estado» | Dos responsabilidades |
La ventaja de respetarlo no es estética, es económica. Una función con una sola responsabilidad tiene una sola razón para cambiar. El día que Estudio Alba decida aceptar días con decimales, tocas pedir_entero y nada más. Si esa misma función también pintara la ficha, cambiar el formato de la ficha te obligaría a tocar código de validación, con el riesgo de romperlo sin darte cuenta.
- Tamaño y nivel de abstracción
De la regla anterior se sigue un tamaño típico: entre tres y veinte líneas. No es una ley, es una consecuencia: una función que ocupa sesenta líneas casi siempre está haciendo varias cosas. Y hay una señal muy fiable de que se ha pasado: si para explicársela a alguien tienes que decir «primero hace esto, luego esto otro, y al final aquello», esos tres pasos quieren ser tres funciones. El segundo criterio, más sutil pero muy potente, es el nivel de abstracción homogéneo: dentro de una misma función, todas las líneas deberían contar la historia a la misma altura. Compara estas dos versiones de lo mismo:
def procesar_tarea(): # niveles MEZCLADOS
titulo, responsable, prioridad, dias = registrar_tarea() # alto nivel
print("=" * 46) # bajo nivel
print(f"{'Titulo':<14}{titulo:>32}") # bajo nivel
print("-" * 46) # bajo nivel
def procesar_tarea(): # nivel HOMOGENEO
titulo, responsable, prioridad, dias = registrar_tarea()
mostrar_ficha(titulo, responsable, prioridad, dias, False)
pausar()La segunda se lee como un resumen de lo que ocurre; la primera obliga a leer código de formateo para enterarte de la trama. La regla mnemotécnica: una función debe leerse como un índice, no como una novela.
- Diseño descendente: escribir el
main() primero
main() primeroEl diseño descendente (top-down) consiste en escribir primero el programa principal como si las funciones que necesitas ya existieran, y solo después implementarlas. Es contraintuitivo y funciona sorprendentemente bien, porque te obliga a decidir qué necesitas antes de perderte en el cómo:
def main():
"""Bucle principal de la aplicacion."""
while True:
mostrar_menu()
opcion = pedir_opcion("Elige una opcion (1-5): ", OPCIONES)
if opcion == "1":
registrar_tarea()
elif opcion == "5":
break
pausar()Ninguna de esas funciones existe todavía, y sin embargo ya has tomado las decisiones importantes: cuántas piezas hay, cómo se llaman y qué recibe cada una. Ese esbozo es a la vez un plan de trabajo y una lista de tareas. El truco práctico para no bloquearte es rellenar los huecos con funciones vacías que solo tengan un pass o un print provisional. Así el programa se ejecuta desde el primer minuto y puedes ir sustituyendo esos esqueletos por implementaciones reales de una en una, comprobando después de cada paso. Es mucho mejor que escribirlo todo y ejecutarlo por primera vez al final, cuando cualquier error puede estar en cualquier sitio.
- El árbol de llamadas
Al descomponer aparece una estructura en capas: el main() llama a funciones de acción y estas llaman a funciones auxiliares. Dibujarla ayuda a detectar desequilibrios:
flowchart TD
M["main()"] --> MM["mostrar_menu() y pausar()"]
M --> PO["pedir_opcion()"]
M --> RT["registrar_tarea()"]
M --> MF["mostrar_ficha()"]
M --> CP["cambiar_prioridad()"]
M --> MC["marcar_completada()"]
RT --> PT["pedir_texto()"]
RT --> PO
RT --> PE["pedir_entero()"]
CP --> PO
MF --> CU["clasificar_urgencia()"]
MC --> CF["confirmar()"]
Tres cosas que este árbol te dice de un vistazo. Primero, que hay dos niveles claros: acciones arriba y utilidades abajo. Segundo, que pedir_opcion la usan tres funciones distintas: es la pieza más reutilizada del programa, y eso confirma que valía la pena extraerla. Y tercero, que ninguna rama baja más de tres niveles, señal de que el programa no está sobre-fragmentado.
- Separar entrada/salida de lógica
Esta es la regla que más mejora un programa por línea de esfuerzo: las funciones que calculan no imprimen ni preguntan. El trabajo se reparte en tres familias:
| Familia | Qué hace | Ejemplos en TareaFácil |
|---|---|---|
| Entrada | Pregunta al usuario y valida | pedir_texto, pedir_entero, confirmar |
| Lógica | Calcula y decide, en silencio | clasificar_urgencia |
| Salida | Presenta resultados | mostrar_menu, mostrar_ficha |
¿Por qué importa tanto? Porque una función de lógica pura es comprobable: le das unas entradas, miras el valor devuelto y sabes si está bien, sin teclear nada ni mirar la pantalla. clasificar_urgencia("alta", 2) debe devolver "CRITICA", y eso se puede verificar mil veces en un segundo; si esa función imprimiera en lugar de devolver, la única forma de comprobarla sería ejecutar la aplicación y leer con los ojos. Esta idea es la base de las pruebas automatizadas. Hay además un beneficio más inmediato: si mañana TareaFácil pasa a tener interfaz gráfica o a generar un informe en un fichero, toda la lógica se salva y solo cambian las funciones de entrada y salida.
- Nombres que describen el efecto
El nombre de una función es un contrato con quien la lee, y hay cuatro señales fáciles de aplicar. La primera son los prefijos: mostrar_* imprime y no devuelve nada útil, obtener_* o calcular_* devuelven y no imprimen, pedir_* pregunta al usuario; cumplirlos hace que el lector acierte sin abrir la función. La segunda: los nombres con «y» delatan dos responsabilidades, así que validar_y_guardar() no es un nombre largo sino un diagnóstico —pártela en validar() y guardar(). La tercera: evita nombres genéricos como procesar, gestionar o datos, porque si no encuentras un nombre concreto suele ser que la función no tiene un propósito concreto. Y la cuarta: el nombre debe advertir de los efectos; una función llamada calcular_total que además pone a cero un contador está mintiendo, y quien la use se llevará una sorpresa desagradable.
- DRY y el exceso contrario
DRY —Don't Repeat Yourself, no te repitas— es el principio que dice que cada pieza de conocimiento debe estar en un solo lugar del programa. Es lo que llevamos aplicando desde 04-01. La forma práctica de aplicarlo es preguntarse, ante dos trozos parecidos, en qué se diferencian. Si la diferencia es un valor —un mensaje, un rango, un catálogo—, ese valor quiere ser un parámetro y los dos trozos quieren ser una función; si la diferencia es estructural, quizá no sean lo mismo y forzar la unión los empeore a los dos. Porque también existe el exceso contrario, la sobre-fragmentación: partir en funciones diminutas que no aportan nada, como un def sumar_uno(n): return n + 1 o un def es_cero(n): return n == 0. Estas funciones alargan el programa y obligan al lector a saltar de sitio en sitio para descubrir que hacían lo obvio. Una función merece existir si se cumple al menos una de estas tres condiciones: se usa más de una vez, su nombre explica algo que el código no dice por sí solo, o oculta una complejidad que ensuciaría a quien la llama. clasificar_urgencia cumple la segunda; pedir_entero cumple las tres; sumar_uno no cumple ninguna.
- El bloque
if __name__ == "__main__":
if __name__ == "__main__":Habrás visto estas dos líneas al final de casi cualquier programa Python, después de todas las definiciones:
__name__ es una variable que Python crea automáticamente en cada fichero. Cuando el fichero se ejecuta directamente (python tareafacil.py), su __name__ vale "__main__" y la condición se cumple, así que main() arranca. Cuando el fichero se importa desde otro para aprovechar sus funciones, __name__ vale en cambio el nombre del fichero ("tareafacil"), la condición es falsa y la aplicación no se lanza sola. Eso es lo que quieres: poder reutilizar clasificar_urgencia desde otro programa sin que se te abra el menú por sorpresa. La teoría completa de la importación es Módulos, paquetes e importaciones; por ahora adopta la forma, que es siempre la misma: define main(), ponla al final junto a las demás definiciones, y cierra el fichero con ese bloque de dos líneas.
- TareaFácil v0.7: el refactor completo
Recordemos el punto de partida. La v0.6 era un único bloque de casi cien líneas seguidas, con esta forma:
# v0.6 (abreviado): todo en un solo bloque
hay_tarea = False # y cinco variables mas de estado
while True:
print("\n" + "=" * ANCHO) # 8 lineas seguidas de menu
opcion = input("Elige una opcion (1-5): ").strip()
while opcion not in OPCIONES: # validacion de la opcion
opcion = input("Opcion no valida. Elige 1-5: ").strip()
if opcion == "1":
... # 15 lineas: confirmacion + CUATRO validaciones
elif opcion == "2":
if not hay_tarea: # comprobacion repetida (1 de 3)
...
elif opcion == "3":
if not hay_tarea: # repetida (2 de 3) + validacion duplicada
...
elif opcion == "4":
if not hay_tarea: # comprobacion repetida (3 de 3)
...
input("\nPulsa Intro para volver al menu...")Y aquí está la v0.7 completa, con las funciones agrupadas por familias:
# tareafacil.py - Estudio Alba
# Version 0.7: programa descompuesto en funciones
ANCHO = 46
PRIORIDADES = ("alta", "media", "baja")
EQUIPO = ("marta", "luis", "nuria")
OPCIONES = ("1", "2", "3", "4", "5")
# --- Entrada: preguntan y validan ---
def pedir_texto(mensaje, obligatorio=True):
"""Pide un texto y lo devuelve sin espacios sobrantes."""
valor = input(mensaje).strip()
while obligatorio and valor == "":
valor = input("No puede estar vacio. " + mensaje).strip()
return valor
def pedir_opcion(mensaje, opciones):
"""Pide un valor hasta que este dentro de las opciones admitidas."""
valor = input(mensaje).strip().lower()
while valor not in opciones:
valor = input(f"No valido. Admitidos: {', '.join(opciones)}. ").strip().lower()
return valor
def pedir_entero(mensaje, minimo, maximo):
"""Pide un entero del rango indicado y lo devuelve ya convertido."""
texto = input(mensaje).strip()
while not texto.isdigit() or not minimo <= int(texto) <= maximo:
texto = input(f"Entero entre {minimo} y {maximo}. ").strip()
return int(texto)
def confirmar(mensaje):
"""Devuelve True solo si el usuario responde 's'."""
return input(f"{mensaje} (s/n): ").strip().lower() == "s"
# --- Logica: calcula, no imprime ---
def clasificar_urgencia(prioridad, dias):
"""Devuelve la etiqueta de urgencia que corresponde a la tarea."""
if prioridad == "alta" and dias <= 2:
return "CRITICA"
if prioridad == "alta":
return "Urgente"
if prioridad == "media" and dias <= 3:
return "Atencion"
return "Normal"
# --- Salida: imprimen, no calculan ---
def mostrar_menu():
"""Pinta la cabecera y las cinco opciones disponibles."""
print("\n" + "=" * ANCHO)
print(f"{'TareaFacil v0.7 - Estudio Alba':^{ANCHO}}")
print("=" * ANCHO)
print(" 1. Registrar / reemplazar la tarea")
print(" 2. Ver la ficha de la tarea")
print(" 3. Cambiar la prioridad")
print(" 4. Marcar como completada")
print(" 5. Salir")
print("-" * ANCHO)
def mostrar_ficha(titulo, responsable, prioridad, dias, completada):
"""Pinta la ficha completa de la tarea indicada."""
estado = "Completada" if completada else "Pendiente"
print("-" * ANCHO)
print(f"{'Titulo':<14}{titulo:>{ANCHO - 14}}")
print(f"{'Responsable':<14}{f'{responsable} ({prioridad})':>{ANCHO - 14}}")
print(f"{'Dias / estado':<14}{f'{dias} / {estado}':>{ANCHO - 14}}")
print(f"{'Urgencia':<14}{clasificar_urgencia(prioridad, dias):>{ANCHO - 14}}")
def pausar():
"""Detiene la ejecucion hasta que el usuario pulsa Intro."""
input("\nPulsa Intro para volver al menu...")
# --- Acciones del menu ---
def registrar_tarea():
"""Pide los datos de una tarea y devuelve los cuatro campos."""
titulo = pedir_texto("Titulo : ")
responsable = pedir_opcion("Responsable : ", EQUIPO).capitalize()
prioridad = pedir_opcion("Prioridad : ", PRIORIDADES)
dias = pedir_entero("Dias (1-365) : ", 1, 365)
return titulo, responsable, prioridad, dias
def cambiar_prioridad(titulo, prioridad):
"""Pide una prioridad nueva y devuelve la que queda vigente."""
nueva = pedir_opcion("Nueva prioridad: ", PRIORIDADES)
print(f"Prioridad de '{titulo}': {prioridad} -> {nueva}")
return nueva
def marcar_completada(titulo, completada):
"""Devuelve el estado de completada tras preguntar al usuario."""
if completada:
print("La tarea ya estaba completada.")
return True
if confirmar(f"Marcar '{titulo}' como completada?"):
print("Tarea completada. Buen trabajo.")
return True
print("Operacion cancelada.")
return False
def main():
"""Ejecuta el bucle principal de la aplicacion."""
hay_tarea = False
titulo = ""
responsable = ""
prioridad = ""
dias = 0
completada = False
while True:
mostrar_menu()
opcion = pedir_opcion("Elige una opcion (1-5): ", OPCIONES)
if opcion == "5":
if confirmar("Seguro que quieres salir?"):
print("Hasta luego. TareaFacil se cierra.")
break
elif opcion == "1":
if hay_tarea and not confirmar(f"Ya existe '{titulo}'. Reemplazarla?"):
print("Operacion cancelada.")
else:
titulo, responsable, prioridad, dias = registrar_tarea()
completada = False
hay_tarea = True
print("Tarea registrada correctamente.")
elif not hay_tarea:
print("Todavia no hay ninguna tarea registrada.")
elif opcion == "2":
mostrar_ficha(titulo, responsable, prioridad, dias, completada)
elif opcion == "3":
prioridad = cambiar_prioridad(titulo, prioridad)
elif opcion == "4":
completada = marcar_completada(titulo, completada)
pausar()
if __name__ == "__main__":
main()Lo que ha cambiado, punto por punto:
- El bucle principal cabe en veinte líneas y se lee como una tabla de decisiones. Ya no hay ni un
inputni unprintde formateo dentro: solo llamadas a funciones con nombre. if not hay_tarea:estaba escrito tres veces; ahora está una. El truco es elelif not hay_tarea:colocado después de las opciones 5 y 1 —las dos únicas que funcionan sin tarea registrada— y antes de las opciones 2, 3 y 4. Si no hay tarea, la cadena deelifse detiene ahí y ninguna de las tres se ejecuta.- Las cuatro validaciones duplicadas son ahora tres funciones, y
pedir_opcionsirve para el menú, para el responsable y para la prioridad.confirmar(mensaje)unifica además las tres confirmaciones y encierra en un solo sitio la decisión de que solo"s"confirma. registrar_tarea()devuelve cuatro valores que se desempaquetan de golpe (04-02), ycambiar_prioridadymarcar_completadadevuelven el nuevo valor en vez de modificarlo por su cuenta: ninguna función toca el estado que no le pertenece, como manda 04-03.
| v0.6 | v0.7 | |
|---|---|---|
| Líneas totales | ~95 | ~150 |
| Líneas del bucle principal | ~75 | 22 |
| Función más larga | 75 (todo el bucle) | 10 (mostrar_menu) |
| Bucles de validación escritos | 5 | 3 (en funciones) |
Comprobaciones not hay_tarea |
3 | 1 |
| Funciones reutilizables fuera del programa | 0 | 8 |
Sí: el fichero tiene más líneas que antes. Es lo normal en un refactor y no es mal negocio, porque lo que se mide no es cuánto ocupa el programa sino cuánto hay que leer para entender un trozo: antes, para saber qué hacía la opción 3, había que leer las setenta y cinco líneas del bucle; ahora se leen cuatro. Queda, eso sí, un cabo suelto, y es grande. Mira la cabecera de mostrar_ficha: cinco parámetros que son siempre los mismos cinco, viajando juntos de función en función. Y mira el principio de main(): seis variables sueltas declaradas una detrás de otra. Esas seis variables son una sola cosa —una tarea— que todavía no tiene forma de ser una sola cosa en nuestro código. Cuando conozcas las tuplas y estructuras anidadas podrás agruparlas, y cuando llegues a las clases podrás darles nombre propio y comportamiento. Hasta entonces, viajan de la mano.
Errores Comunes y Consejos
Extraer funciones que siguen dependiendo de globales. Mover diez líneas a un def no es descomponer si esas líneas siguen leyendo y escribiendo variables del programa principal. Comprueba cada función con la prueba del recorte de 04-03. Y las funciones que hacen dos cosas suelen delatarse en el nombre (validar_y_guardar) o al describirlas: pártelas, aunque cada mitad quede muy corta.
Mezclar niveles de abstracción. Un main() con un print("=" * 46) en medio de llamadas de alto nivel: ese print pertenece a mostrar_menu. El defecto contrario es sobre-fragmentar: veinte funciones de dos líneas usadas una sola vez son tan difíciles de leer como un bloque de doscientas. Refactorizar y añadir funcionalidad a la vez. Es la receta para no saber qué ha roto qué. Primero reorganiza dejando el comportamiento idéntico, comprueba que todo sigue igual, y solo entonces añade lo nuevo. Y no olvides el if __name__ == "__main__":, ni dejes código suelto en el margen izquierdo entre las definiciones: se ejecutará en cuanto alguien importe el fichero.
Consejo: refactoriza en pasos pequeños y ejecuta después de cada uno. Extrae una función, ejecuta, comprueba; si algo falla, sabes exactamente qué paso lo causó. Y escribe el main() como te gustaría que fuera: si al leerlo entiendes el programa sin abrir ninguna otra función, la descomposición es buena, y de paso tienes la mejor documentación que tendrá tu programa.
Ejercicios
Ejercicio 1: Descomponer un guion
Este programa funciona pero está escrito de un tirón. Identifica sus responsabilidades, propón los nombres de las funciones en que lo partirías —indicando parámetros y qué devuelve cada una— y escribe el main() resultante.
nombre = input("Cliente: ").strip()
while nombre == "":
nombre = input("No puede estar vacio. Cliente: ").strip()
horas = input("Horas: ").strip()
while not horas.isdigit() or int(horas) < 1:
horas = input("Entero mayor que 0. Horas: ").strip()
horas = int(horas)
importe = horas * 55.0
if horas > 40:
importe = importe * 0.9 # descuento del 10% por volumen
print("=" * 40)
print(f"Cliente: {nombre}")
print(f"Importe: {importe:.2f} EUR")Ejercicio 2: Diagnosticar una descomposición
Un compañero ha partido su programa en estas tres funciones. Señala cuatro defectos de diseño, cada uno con el criterio de la lección que incumple, y propón una alternativa.
def procesar(): # declara 'global total'
datos = input("Dato: ") # pide un dato al usuario
total = total + int(datos) # actualiza la global
print(f"Total: {total}") # lo imprime
return total # y ademas lo devuelve
def sumar_dos(a, b):
return a + b
def validar_y_mostrar_cliente(nombre): # si esta vacio avisa; si no, lo imprime
...Soluciones
Solución 1. Hay cuatro responsabilidades: pedir el nombre validado, pedir las horas validadas, calcular el importe con su descuento y presentar el recibo. La lógica del descuento debe quedar aislada de la entrada y de la salida.
TARIFA = 55.0
ANCHO = 40
def pedir_texto(mensaje):
"""Pide un texto obligatorio y lo devuelve limpio."""
valor = input(mensaje).strip()
while valor == "":
valor = input("No puede estar vacio. " + mensaje).strip()
return valor
def pedir_entero_positivo(mensaje):
"""Pide un entero mayor que cero y lo devuelve convertido."""
texto = input(mensaje).strip()
while not texto.isdigit() or int(texto) < 1:
texto = input("Entero mayor que 0. " + mensaje).strip()
return int(texto)
def calcular_importe(horas, tarifa=TARIFA):
"""Devuelve el importe, con un 10% de descuento por encima de 40 horas."""
importe = horas * tarifa
if horas > 40:
return importe * 0.9
return importe
def mostrar_recibo(nombre, importe):
"""Pinta el recibo enmarcado del cliente."""
print("=" * ANCHO)
print(f"Cliente: {nombre}")
print(f"Importe: {importe:.2f} EUR")
def main():
"""Pide los datos del encargo y muestra el recibo."""
nombre = pedir_texto("Cliente: ")
horas = pedir_entero_positivo("Horas: ")
mostrar_recibo(nombre, calcular_importe(horas))
if __name__ == "__main__":
main()Fíjate en que calcular_importe no imprime ni pregunta: puedes comprobar a mano que calcular_importe(40) da 2200.0 y calcular_importe(41) da 2029.5, sin ejecutar el programa. Y en que el main() tiene tres líneas que se leen como el enunciado del problema.
Solución 2.
| Defecto | Criterio incumplido | Alternativa |
|---|---|---|
procesar usa global total |
Una función no debe depender de estado global cambiante (04-03) | def acumular(total, dato): return total + dato |
procesar pide, calcula, imprime y devuelve |
Una función, una responsabilidad | Separar en pedir_entero, acumular y mostrar_total |
sumar_dos es sobre-fragmentación |
No se reutiliza, no aclara nada, no oculta complejidad | Escribir a + b donde haga falta |
validar_y_mostrar_cliente lleva «y» en el nombre |
Dos responsabilidades: validar y presentar | def es_nombre_valido(nombre): return nombre != "" más mostrar_cliente(nombre) |
Además, el nombre procesar es genérico y no advierte de que modifica el estado global. Un nombre honesto para lo que hace sería pedir_dato_y_acumularlo_en_total: su misma fealdad demuestra que la función está mal partida.
Conclusión
Descomponer un programa no es cortarlo en trozos: es encontrar sus partes. Los criterios son pocos y comprobables: una función, una responsabilidad, verificable con la prueba de describirla sin usar «y»; un tamaño que rara vez pasa de veinte líneas; un nivel de abstracción homogéneo dentro de cada función; entrada, lógica y salida en familias separadas, porque la lógica silenciosa es la única que se puede comprobar de verdad; nombres que anuncian el efecto; DRY para no repetirse, y sentido común para no fragmentar de más. El diseño descendente —escribir el main() como si las funciones ya existieran— es la forma más cómoda de aplicar todo eso, y el bloque if __name__ == "__main__": cierra el fichero para que pueda ejecutarse o importarse.
TareaFácil ha llegado a la versión 0.7. Hace exactamente lo mismo que la v0.6 —ni una función nueva de cara a Marta—, pero su bucle principal ha pasado de setenta y cinco líneas a veintidós, la duplicación ha desaparecido y ocho de sus funciones se pueden reutilizar tal cual en otro programa. El estado de la tarea, eso sí, sigue viviendo en seis variables sueltas que hay que pasar de función en función: es la deuda que el módulo 5 y el 7 vendrán a cobrar. Queda una última sorpresa antes de cerrar el módulo. Hasta ahora las funciones han sido cosas que se llaman; pero en 04-01 viste de pasada que pausar sin paréntesis es un valor con su propio type(). Si una función es un valor, se puede guardar en una variable, pasar como argumento a otra función y devolver desde otra. Eso abre una forma de programar distinta, y es el cierre del módulo: Funciones como valores: lambda y orden superior.
Fundamentos de la Programación
Módulo 1: Introducción a la Programación
- ¿Qué es la programación?
- Historia de la programación
- Lenguajes de programación
- Entornos de desarrollo
- Del problema al algoritmo
Módulo 2: Conceptos Básicos
- Variables y tipos de datos
- Operadores y expresiones
- Entrada y salida de datos
- Conversión de tipos y validación de datos
Módulo 3: Estructuras de Control
Módulo 4: Funciones y Procedimientos
- Definición y uso de funciones
- Parámetros y retorno de valores
- Ámbito de variables
- Descomponer un programa en funciones
- Funciones como valores: lambda y orden superior
Módulo 5: Estructuras de Datos
- Listas y arreglos
- Cadenas de caracteres
- Diccionarios y conjuntos
- Tuplas y estructuras anidadas
- Guardar datos en archivos: texto, CSV y JSON
Módulo 6: Algoritmos Básicos
Módulo 7: Objetos y Organización del Código
- De los datos a los objetos: clases e instancias
- Atributos, métodos y constructor
- Colecciones de objetos
- Módulos, paquetes e importaciones
Módulo 8: Buenas Prácticas y Herramientas
- Documentación y comentarios
- Depuración y manejo de errores
- Control de versiones
- Pruebas automatizadas
- Estilo, legibilidad y refactorización
