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

  1. Una función, una responsabilidad
  2. Tamaño y nivel de abstracción
  3. Diseño descendente: escribir el main() primero
  4. El árbol de llamadas
  5. Separar entrada/salida de lógica
  6. Nombres que describen el efecto
  7. DRY y el exceso contrario
  8. El bloque if __name__ == "__main__":
  9. TareaFácil v0.7: el refactor completo
  10. Errores comunes y consejos
  11. Ejercicios
  12. Conclusión

  1. 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.

  1. 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.

  1. Diseño descendente: escribir el main() primero

El 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.

  1. 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.

  1. 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.

  1. 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.

  1. DRY y el exceso contrario

DRYDon'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.

  1. El bloque if __name__ == "__main__":

Habrás visto estas dos líneas al final de casi cualquier programa Python, después de todas las definiciones:

if __name__ == "__main__":
    main()

__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.

  1. 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 input ni un print de formateo dentro: solo llamadas a funciones con nombre.
  • if not hay_tarea: estaba escrito tres veces; ahora está una. El truco es el elif 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 de elif se detiene ahí y ninguna de las tres se ejecuta.
  • Las cuatro validaciones duplicadas son ahora tres funciones, y pedir_opcion sirve 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), y cambiar_prioridad y marcar_completada devuelven 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

Módulo 2: Conceptos Básicos

Módulo 3: Estructuras de Control

Módulo 4: Funciones y Procedimientos

Módulo 5: Estructuras de Datos

Módulo 6: Algoritmos Básicos

Módulo 7: Objetos y Organización del Código

Módulo 8: Buenas Prácticas y Herramientas

Módulo 9: Proyecto Final y Cierre del Curso

© Copyright 2026. Todos los derechos reservados