Ya sabes decidir con if y repetir con for y while, pero tus bucles todavía son rígidos: recorren la secuencia completa sí o sí. En esta lección aprenderás a tomar el control fino de la ejecución: break para salir de un bucle en cuanto encuentres lo que buscas, continue para saltarte elementos, pass como marcador de posición, la poco conocida cláusula else de los bucles, el patrón while True para menús que se repiten hasta que el usuario decide salir, y la moderna sentencia match/case de Python 3.10. Con todas ellas construiremos el primer menú interactivo de Papyrus, el esqueleto sobre el que crecerá la aplicación de Ana durante el resto del curso.

Contenido

  1. break: salir del bucle antes de tiempo
  2. continue: saltar a la siguiente iteración
  3. pass: la instrucción que no hace nada
  4. La cláusula else en bucles
  5. Bucles infinitos controlados: while True + break
  6. match/case: selección por patrones (Python 3.10+)
  7. Proyecto: el menú interactivo de Papyrus

break: salir del bucle antes de tiempo

La sentencia break ("romper") termina el bucle inmediatamente: Python salta a la primera instrucción después del bucle, sin completar la vuelta actual ni hacer las restantes.

El caso de uso por excelencia es la búsqueda: Luis pregunta si Papyrus tiene Hamlet. En cuanto lo encontramos, no tiene sentido seguir mirando el resto del catálogo.

catalogo = ["La Odisea", "Hamlet", "El Quijote"]
buscado = "Hamlet"

for titulo in catalogo:
    print(f"Comprobando '{titulo}'...")
    if titulo == buscado:
        print(f"¡Encontrado! '{buscado}' está en el catálogo.")
        break

print("Búsqueda terminada.")

Salida:

Comprobando 'La Odisea'...
Comprobando 'Hamlet'...
¡Encontrado! 'Hamlet' está en el catálogo.
Búsqueda terminada.

Fíjate: El Quijote nunca se comprueba. Con un catálogo de 3 libros da igual, pero con 30 000 la diferencia es enorme.

Detalles importantes de break:

  • Solo se puede usar dentro de un bucle (for o while); fuera produce SyntaxError.
  • En bucles anidados, break sale solo del bucle más interno que lo contiene, no de todos.
  • Casi siempre aparece dentro de un if: "si pasa esto, deja de iterar".

continue: saltar a la siguiente iteración

Mientras break abandona el bucle, continue ("continuar") abandona solo la vuelta actual: salta directamente a la siguiente iteración, sin ejecutar el resto del bloque.

Ana quiere imprimir la lista de libros vendibles, saltándose los agotados:

catalogo = ["La Odisea", "Hamlet", "El Quijote", "Fausto"]
stocks = [4, 6, 8, 0]

print("Libros disponibles para la venta:")
for i, titulo in enumerate(catalogo):
    if stocks[i] == 0:
        continue    # agotado: pasamos al siguiente sin imprimir nada
    print(f"- {titulo} ({stocks[i]} uds.)")

Salida:

Libros disponibles para la venta:
- La Odisea (4 uds.)
- Hamlet (6 uds.)
- El Quijote (8 uds.)

Fausto (recién llegado al catálogo, pero con stock 0) se salta limpiamente. El patrón if condición_de_descarte: continue al principio del bloque se llama a veces "cláusula de guarda" y tiene una gran ventaja de legibilidad: el caso "normal" del bucle queda sin indentación extra, en lugar de envolverlo todo en un if gigante.

Comparativa rápida de las dos sentencias:

Sentencia Qué interrumpe El bucle... Uso típico
break El bucle entero Termina ya "Encontrado, dejo de buscar"
continue Solo la vuelta actual Sigue con la siguiente "Este elemento no me interesa, siguiente"
flowchart TD
    A[Siguiente elemento] --> B{¿descartar?}
    B -- "continue" --> A
    B -- No --> C[Procesar elemento]
    C --> D{¿objetivo cumplido?}
    D -- "break" --> E[Salir del bucle]
    D -- No --> A

pass: la instrucción que no hace nada

pass es exactamente eso: una sentencia vacía. Existe porque la sintaxis de Python exige que todo bloque indentado contenga al menos una instrucción; cuando aún no sabes qué poner (o deliberadamente no quieres hacer nada), pass rellena el hueco sin efectos.

opcion = "3"

if opcion == "1":
    print("Mostrando catálogo...")
elif opcion == "2":
    pass    # TODO: búsqueda de libros, la implementaremos más abajo
else:
    print("Opción no reconocida.")

Sin el pass, ese elif con el cuerpo vacío daría IndentationError. Sus usos habituales:

  • Esqueletos: escribir primero la estructura del programa (ramas, bucles, y en el futuro funciones y clases) y rellenar los bloques poco a poco.
  • Ignorar casos a propósito, dejando constancia explícita de que no es un olvido.

No confundas pass con continue: dentro de un bucle, pass no salta nada (la ejecución sigue en la línea siguiente); simplemente "no hace nada" y continúa el flujo normal.

La cláusula else en bucles

Aquí llega una peculiaridad muy de Python: los bucles for y while pueden llevar un bloque else. Su significado sorprende al principio: el else se ejecuta si el bucle terminó de forma natural, sin break.

¿Para qué sirve? Para el patrón de búsqueda que vimos antes: ¿qué pasa si el libro no está? Sin else necesitaríamos una variable "bandera" (flag):

# Versión con bandera (funciona, pero más ruido)
catalogo = ["La Odisea", "Hamlet", "El Quijote"]
buscado = "Fausto"
encontrado = False

for titulo in catalogo:
    if titulo == buscado:
        encontrado = True
        break

if encontrado:
    print(f"'{buscado}' está en el catálogo.")
else:
    print(f"'{buscado}' no está. Ana puede pedirlo al distribuidor.")

Con el else del bucle, la bandera desaparece:

# Versión con for/else (idiomática en Python)
catalogo = ["La Odisea", "Hamlet", "El Quijote"]
buscado = "Fausto"

for titulo in catalogo:
    if titulo == buscado:
        print(f"'{buscado}' está en el catálogo.")
        break
else:
    print(f"'{buscado}' no está. Ana puede pedirlo al distribuidor.")

Salida:

'Fausto' no está. Ana puede pedirlo al distribuidor.

Cómo leerlo sin confundirse: piensa en el else del bucle como un "si no hubo break" (algunos lo llaman la cláusula nobreak). El flujo exacto:

  • El bucle recorre todos los elementos sin que se ejecute break → al acabar, se ejecuta el else.
  • Se ejecuta un break en cualquier vuelta → el else se salta.

Dos advertencias:

  • El else va alineado con el for/while, no con ningún if interior. Un despiste de indentación cambia el significado por completo.
  • Es una construcción poco conocida incluso entre programadores con experiencia; úsala para búsquedas (su caso estrella) y acompáñala de un comentario si crees que quien lea el código puede no conocerla.

También funciona con while: el else se ejecuta cuando la condición se vuelve falsa (salida natural), pero no si sales con break.

Bucles infinitos controlados: while True + break

En la lección anterior el bucle infinito era un error a evitar. Pero hay una versión deliberada y controlada que es un patrón fundamental: while True con un break interior. Se usa cuando el programa debe repetir algo indefinidamente hasta que el usuario decida parar — exactamente lo que hace cualquier menú, cajero automático o aplicación interactiva.

while True:
    respuesta = input("Escribe 'salir' para terminar: ")
    if respuesta == "salir":
        print("¡Hasta pronto!")
        break
    print(f"Has escrito: {respuesta}")

Como True es siempre verdadero, el bucle no termina nunca por su condición: la única salida es el break. Esto no es un bucle infinito accidental, porque la salida existe y está clara; la clave es garantizar que el break es alcanzable.

Este patrón también resuelve del todo la validación de entradas que dejamos a medias en ficha_libro.py:

while True:
    texto = input("Stock inicial del libro: ")
    if texto.isdigit():          # ¿la cadena contiene solo dígitos?
        stock = int(texto)
        break
    print("Entrada no válida. Escribe un número entero, por ejemplo: 4")

print(f"Stock registrado: {stock}")

isdigit() es un método de las cadenas que devuelve True si todos sus caracteres son dígitos (lo veremos junto al resto de métodos de str en el módulo 4; de momento, úsalo tal cual). El bucle insiste hasta recibir un número válido, y solo entonces convierte y sale. Comparado con el while respuesta != ... de la lección anterior, esta forma evita duplicar el input() o inicializar variables artificiales: por eso es la preferida en Python.

match/case: selección por patrones (Python 3.10+)

Cuando un programa debe reaccionar de forma distinta según el valor concreto de una variable (la opción de un menú, un código de estado, un tipo de cliente), una cadena de if/elif funciona, pero desde Python 3.10 existe una alternativa más expresiva: la sentencia match.

opcion = "2"

match opcion:
    case "1":
        print("Mostrando el catálogo completo...")
    case "2":
        print("Buscador de libros...")
    case "3":
        print("Saliendo de Papyrus. ¡Hasta mañana, Ana!")
    case _:
        print("Opción no válida.")

Cómo funciona:

  • match expresion: evalúa la expresión una vez.
  • Cada case patron: se compara en orden; el primero que encaja ejecuta su bloque y la sentencia termina (no hay "caída" al siguiente caso, a diferencia del switch de otros lenguajes: no necesitas ningún break aquí).
  • case _: es el comodín: encaja con cualquier cosa, y actúa como el else final. Debe ir en último lugar.
  • Si ningún caso encaja y no hay comodín, simplemente no se ejecuta nada (sin error).

Además de valores literales, los patrones básicos permiten dos cosas muy útiles:

Alternativas con | (o barra vertical): un mismo caso para varios valores.

respuesta = input("¿Confirmar la venta? (s/n): ")

match respuesta:
    case "s" | "S" | "si" | "sí":
        print("Venta confirmada.")
    case "n" | "N" | "no":
        print("Venta cancelada.")
    case _:
        print("Respuesta no reconocida.")

Condición extra con if (llamada guarda): el caso solo encaja si además se cumple la condición.

stock = 2

match stock:
    case 0:
        print("Agotado.")
    case n if n <= 3:
        print(f"Stock bajo: quedan {n}.")
    case n:
        print(f"Stock correcto: {n} unidades.")

En case n if n <= 3:, el patrón n es un patrón de captura: encaja con cualquier valor y lo guarda en la variable n, pero la guarda if n <= 3 filtra cuándo se acepta. Es una puerta de entrada a los patrones estructurales más avanzados de match (desempaquetar listas, diccionarios u objetos), que cobrarán sentido cuando conozcas esas estructuras en los módulos 4 y 5.

¿match o if/elif? Guía rápida:

Situación Recomendación
Comparar una misma variable contra valores concretos (menús, códigos) match gana en claridad
Condiciones heterogéneas (stock > 0 and es_socio, rangos, varios datos) if/elif
Tu código debe funcionar en Python < 3.10 if/elif obligatoriamente

Proyecto: el menú interactivo de Papyrus

Juntemos todas las piezas de la lección en un script nuevo para el proyecto: menu.py, dentro de la carpeta papyrus (con el .venv activado, como siempre). Es el primer programa de Papyrus que conversa con Ana: se repite hasta que ella decide salir.

NOMBRE_TIENDA = "Papyrus"
catalogo = ["La Odisea", "Hamlet", "El Quijote"]
precios = [12.50, 9.95, 15.90]
stocks = [4, 6, 8]

print(f"Bienvenida a la gestión de {NOMBRE_TIENDA}")

while True:
    print()
    print("1. Ver catálogo")
    print("2. Buscar un libro")
    print("3. Salir")
    opcion = input("Elige una opción (1-3): ")

    match opcion:
        case "1":
            print(f"\n{'Título':<12} {'Precio':>8} {'Stock':>6}")
            print("-" * 28)
            for i, titulo in enumerate(catalogo):
                print(f"{titulo:<12} {precios[i]:>6.2f} € {stocks[i]:>6}")
        case "2":
            buscado = input("Título a buscar: ")
            if not buscado:
                print("No has escrito nada.")
                continue
            for i, titulo in enumerate(catalogo):
                if titulo.lower() == buscado.lower():
                    print(f"'{titulo}': {precios[i]:.2f} €, stock {stocks[i]}.")
                    break
            else:
                print(f"'{buscado}' no está en el catálogo.")
        case "3":
            print(f"Cerrando {NOMBRE_TIENDA}. ¡Hasta mañana, Ana!")
            break
        case _:
            print("Opción no válida. Elige 1, 2 o 3.")

Repasa cómo colabora cada herramienta:

  1. while True mantiene el menú vivo: tras cada operación, vuelve a mostrarse.
  2. match opcion despacha cada opción con un caso limpio, y case _ captura los errores de tecleo.
  3. En la búsqueda, continue actúa de guarda si Ana pulsa Intro sin escribir (truthiness de la cadena vacía, como en la lección 02-01): vuelve al menú sin ejecutar la búsqueda.
  4. for/break/else: el break corta en cuanto hay coincidencia y el else del bucle cubre el caso "no encontrado" sin variables bandera. (lower() pasa el texto a minúsculas para que la búsqueda no distinga mayúsculas; más sobre métodos de cadenas en el módulo 4.)
  5. break en el case "3" es la única salida del while True: fíjate en que rompe el bucle exterior porque match no es un bucle — break y continue atraviesan la sentencia match y actúan sobre el bucle que la contiene.

Una sesión de ejemplo:

Bienvenida a la gestión de Papyrus

1. Ver catálogo
2. Buscar un libro
3. Salir
Elige una opción (1-3): 2
Título a buscar: hamlet
'Hamlet': 9.95 €, stock 6.

1. Ver catálogo
2. Buscar un libro
3. Salir
Elige una opción (1-3): 3
Cerrando Papyrus. ¡Hasta mañana, Ana!

Este menú es deliberadamente sencillo: en el módulo 3 lo reorganizaremos con funciones (una por opción) y en el módulo 6 hará que el catálogo sobreviva entre sesiones guardándolo en archivos. El esqueleto, sin embargo, ya no cambiará: while True + match + break es el patrón estándar de las aplicaciones de consola.

Errores Comunes y Consejos

  • Esperar que break salga de todos los bucles anidados: solo sale del más interno. Si necesitas salir de varios niveles, suele ser señal de que ese código merece ser una función (módulo 3), donde return sale de todo de golpe.
  • Malinterpretar el else del bucle como "si el bucle no se ejecutó ninguna vez": falso. Con una secuencia vacía, el bucle termina sin break... y el else se ejecuta. Recuerda: else = "no hubo break".
  • Usar break o continue fuera de un bucle (por ejemplo, dentro de un if suelto o esperando que corten un match): SyntaxError. Solo tienen sentido dentro de for/while.
  • Abusar de continue: varias guardas seguidas al inicio del bucle son legibles; continues repartidos por mitad del bloque hacen el flujo difícil de seguir. Si te pasa, replantea las condiciones.
  • Olvidar el break de salida en un while True: entonces sí tienes un bucle infinito de verdad. Al escribir while True:, escribe el case/if de salida con su break antes de rellenar el resto.
  • Escribir case "1" | "2": cuando cada valor necesita lógica distinta: la alternativa | es para casos que comparten bloque. Si los bloques difieren, son casos separados.
  • Usar match con Python antiguo: en versiones anteriores a 3.10 da SyntaxError. Comprueba tu versión con python --version; si mantienes código para versiones viejas, usa if/elif.
  • Consejo: pass es útil mientras construyes, pero no debería llegar a la versión final del script salvo que ignorar el caso sea una decisión consciente — y entonces, coméntalo.

Ejercicios

Ejercicio 1: primera venta agotada

Dadas ventas_pendientes = [2, 1, 3, 2, 4] (unidades pedidas por varios clientes, en orden) y un stock = 6 de Hamlet, recorre los pedidos con un for: sirve cada pedido restando del stock e imprime Pedido de N uds. servido (quedan M). Si un pedido no puede servirse completo, imprime Stock insuficiente para el pedido de N uds. y deja de procesar pedidos en ese momento. Si todos se sirvieron, imprime al final Todos los pedidos servidos (pista: for/else).

Ejercicio 2: informe saltando descatalogados

Dadas las listas titulos = ["La Odisea", "Hamlet", "El Quijote", "Fausto"] y estados = ["activo", "activo", "descatalogado", "activo"], imprime un informe numerado (empezando en 1) solo de los libros activos, usando continue para saltar los descatalogados. La numeración debe ser consecutiva para los mostrados (1, 2, 3), no la posición original.

Ejercicio 3: cajero de Papyrus con match

Escribe un while True que pida a Ana un código de operación y reaccione con match:

  • "v" o "venta" → pide un importe y súmalo a un acumulador caja (parte de caja = 0.0).
  • "d" o "devolucion" → pide un importe y réstalo de caja.
  • "t" → imprime el total actual con dos decimales.
  • "x" → imprime el total final y sale.
  • Cualquier otra cosa → mensaje de error.

Soluciones

Solución 1:

ventas_pendientes = [2, 1, 3, 2, 4]
stock = 6

for pedido in ventas_pendientes:
    if pedido > stock:
        print(f"Stock insuficiente para el pedido de {pedido} uds.")
        break
    stock -= pedido
    print(f"Pedido de {pedido} uds. servido (quedan {stock})")
else:
    print("Todos los pedidos servidos")

Con stock 6, se sirven los pedidos de 2 y 1 (quedan 3), el de 3 (quedan 0) y el de 2 ya no puede servirse: break. Como hubo break, el else no se ejecuta — exactamente lo que queremos. Prueba a cambiar stock = 12 y verás el mensaje final.

Solución 2:

titulos = ["La Odisea", "Hamlet", "El Quijote", "Fausto"]
estados = ["activo", "activo", "descatalogado", "activo"]

numero = 0
for i, titulo in enumerate(titulos):
    if estados[i] == "descatalogado":
        continue
    numero += 1
    print(f"{numero}. {titulo}")

La clave está en llevar un contador propio (numero) que solo se incrementa después de la guarda con continue: así los descatalogados no consumen número y la lista mostrada queda 1. La Odisea, 2. Hamlet, 3. Fausto.

Solución 3:

caja = 0.0

while True:
    codigo = input("Operación (v/d/t/x): ")
    match codigo:
        case "v" | "venta":
            caja += float(input("Importe de la venta: "))
        case "d" | "devolucion":
            caja -= float(input("Importe devuelto: "))
        case "t":
            print(f"Total en caja: {caja:.2f} €")
        case "x":
            print(f"Cierre. Total final: {caja:.2f} €")
            break
        case _:
            print("Código no reconocido. Usa v, d, t o x.")

El patrón completo de la lección en miniatura: while True como corazón del programa, | para aceptar sinónimos, case _ para errores de tecleo y un único break como salida. Como siempre, float() fallará si Ana escribe texto en el importe — la red de seguridad llegará en el módulo 7.

Conclusión

Tus bucles han dejado de ser trenes sin frenos: con break paras en cuanto encuentras lo que buscas, con continue te saltas lo que no interesa, con pass reservas el sitio de lo que está por escribir, con el else de los bucles detectas búsquedas sin éxito sin variables bandera, y con while True + break has construido el patrón universal de los programas interactivos. Además, match/case te da una forma moderna y legible de despachar opciones. Todo ello quedó ensamblado en menu.py, el primer programa de Papyrus que dialoga con Ana y el esqueleto de todo lo que viene.

Hay un último superpoder de este módulo. Habrás notado que muchos de nuestros bucles siguen el mismo patrón: recorrer una lista para construir otra (precios con IVA, títulos filtrados por stock...). Python tiene una sintaxis específica, compacta y elegantísima para ese patrón: las comprensiones de listas. Son la seña de identidad del código pythónico, y con ellas cerraremos el módulo en la próxima lección.

Curso de Programación en Python

Módulo 1: Introducción a Python

Módulo 2: Estructuras de Control

Módulo 3: Funciones y Módulos

Módulo 4: Estructuras de Datos

Módulo 5: Programación Orientada a Objetos

Módulo 6: Manejo de Archivos

Módulo 7: Manejo de Errores y Excepciones

Módulo 8: Temas Avanzados

Módulo 9: Pruebas y Depuración

Módulo 10: Desarrollo Web con Python

Módulo 11: Ciencia de Datos con Python

Módulo 12: Proyecto Final

© Copyright 2026. Todos los derechos reservados