Semana 2: Flujo de Control
🎯 Objetivos de aprendizaje
Al final de esta semana podrás:
- Ramificar el comportamiento de un programa con
if/elif/else. - Combinar condiciones con
and,orynot. - Repetir trabajo con bucles
whileyfor, y elegir el correcto. - Usar
range()para iterar un número fijo de veces, ybreak/continuepara controlar un bucle antes de tiempo. - Anidar bucles y condicionales para resolver problemas con más de una parte móvil.
Lección
Ramificación: if / elif / else
Una sentencia if es una definición por partes. Compara:
x = -3
if x < 0:
print("negative")
elif x == 0:
print("zero")
else:
print("positive")
La indentación aquí no es un asunto de estilo — es la sintaxis. Todo lo indentado bajo if pertenece a esa rama; Python no tiene { } para marcar bloques. Un bloque necesita al menos una sentencia — si quieres una rama que deliberadamente no haga nada (por ejemplo, mientras esbozas la forma de un programa antes de completarlo), usa pass, una sentencia cuyo único trabajo es no hacer nada:
if x < 0:
pass # TODO: manejar números negativos más adelante
else:
print("non-negative")
Combinar condiciones: and, or, not
Igual que , , en lógica, Python tiene and, or, not para combinar expresiones booleanas:
age = 20
has_ticket = True
if age >= 18 and has_ticket:
print("Welcome in")
if age < 13 or age > 65:
print("Discount applies")
if not has_ticket:
print("Buy a ticket first")
Siguen las mismas tablas de verdad que esperarías: and es verdadero solo cuando ambos lados son verdaderos; or es verdadero cuando al menos uno de los lados es verdadero; not invierte un booleano. Python también hace evaluación de cortocircuito: en a and b, si a ya es False, Python ni siquiera evalúa b, ya que la expresión completa debe ser False sin importar lo demás. Esto importa cuando evaluar b podría ser costoso o inseguro — por ejemplo, x != 0 and 10 / x > 1 nunca corre el riesgo de dividir entre cero, porque si x != 0 es False, la división se omite por completo.
while: repetir hasta que una condición falle
Un bucle while es lo más parecido a una recurrencia matemática con una condición de parada:
n = 5
while n > 0:
print(n)
n = n - 1
print("liftoff!")
Esto imprime 5 4 3 2 1 liftoff!. El bucle vuelve a comprobar n > 0 antes de cada iteración — si olvidas actualizar n dentro del bucle, nunca se vuelve falso, y obtienes un bucle infinito.
while es la herramienta correcta cuando no sabes de antemano cuántas iteraciones necesitarás — la condición de parada depende de algo que ocurre durante el bucle, como la entrada del usuario o una búsqueda que podría terminar antes:
guess = None
target = 42
while guess != target:
guess = int(input("Guess the number: "))
print("Correct!")
for: repetir sobre una secuencia conocida
Un bucle for recorre directamente una secuencia de valores — piénsalo como donde es lo que sea que estés recorriendo, salvo que estás ejecutando código para cada en lugar de sumar números:
for letter in "cat":
print(letter) # c, a, t — uno por línea
range(n) produce la secuencia — exactamente el conjunto de índices que usarías para :
total = 0
for i in range(5):
total = total + i
print(total) # 0+1+2+3+4 = 10
range(start, stop) y range(start, stop, step) generalizan esto, reflejando una secuencia aritmética :
for i in range(2, 10, 2):
print(i) # 2, 4, 6, 8 — empieza en 2, se detiene antes de 10, avanza de 2 en 2
Un paso negativo cuenta hacia atrás: range(5, 0, -1) produce 5, 4, 3, 2, 1, la misma secuencia que el ejemplo de "liftoff" con while de la Semana 1 construyó a mano.
break y continue
break sale de un bucle inmediatamente; continue salta a la siguiente iteración sin terminar la actual:
for i in range(10):
if i == 5:
break # se detiene por completo cuando i llega a 5
if i % 2 == 0:
continue # se salta la impresión de los números pares
print(i) # imprime 1, 3
Anidamiento: bucles y condicionales unos dentro de otros
El cuerpo de un bucle —o una rama de if— puede contener otro bucle u otro if, exactamente igual que los casos de una función por partes pueden a su vez involucrar más condiciones. Cada nivel de anidamiento añade un nivel más de indentación:
for row in range(1, 4):
for col in range(1, 4):
print(row * col, end=" ") # end=" " imprime un espacio en vez de un salto de línea
print() # pasa a la siguiente línea después de cada fila
Esto imprime una pequeña tabla de multiplicar de 3×3:
1 2 3
2 4 6
3 6 9
El bucle interno se ejecuta hasta completarse en cada iteración del bucle externo — con 3 iteraciones externas y 3 internas cada una, son sentencias print en total, el mismo principio de conteo detrás de una suma doble .
⚠️ Errores comunes
- Errores de desfase (off-by-one) con
range.range(1, 10)se detiene antes de 10, dando1..9. Si quieres incluir el 10, necesitasrange(1, 11). - Olvidar actualizar la variable del bucle en un
while.while n > 0: print(n)sinn -= 1dentro nunca termina. - Usar
=en lugar de==en una condición. Python en realidad te protege de esto (if x = 5:es unSyntaxError), a diferencia de otros lenguajes — pero sigue valiendo la pena saber por qué sería un error si estuviera permitido. - Asumir que las cadenas de
elifcomprueban todas las ramas. En cuanto una condiciónelif/ifcoincide, el resto se omite por completo — el orden importa, especialmente con condiciones superpuestas como el caso "divisible entre 3 y 5 a la vez" de FizzBuzz.
🧩 Retos
Escribe "FizzBuzz" para los números del 1 al 10: imprime "Fizz" si es divisible entre 3, "Buzz" si es divisible entre 5, "FizzBuzz" si es divisible entre ambos, y en caso contrario el número mismo.
Escribe un bucle que siga preguntando "Type 'quit' to stop: " hasta que el estudiante escriba exactamente quit. ¿Encajaría mejor for o while para esta tarea, y por qué?
Suma los enteros del 1 al 100 usando un bucle, y verifica la respuesta de tu programa contra la fórmula en forma cerrada .
Escribe un programa que lea un número n e indique si es primo, comprobando si algún entero desde 2 hasta (sin incluir) n lo divide exactamente.
Usando bucles anidados, imprime un cuadrado de asteriscos, n filas por n columnas, para un número n que elijas (por ejemplo, un bloque de 4×4 de caracteres *).
Escribe una condición usando and que compruebe si una variable age está entre 18 y 65 (incluyendo el 18, excluyendo el 65) y un booleano has_ticket es True.
🤔 Preguntas socráticas
- ¿Qué ocurre si escribes
while True:sin ningúnbreakdentro? Pruébalo con cuidado en el playground (puede que necesites detener la ejecución manualmente) — ¿por qué esto es distinto de un bucleforsobre unrangefijo? - En FizzBuzz, ¿por qué el caso de divisibilidad entre ambos (
FizzBuzz) necesita comprobarse antes de las comprobaciones separadas deFizz/Buzz, o manejarse conand? ¿Qué saldría mal con un orden ingenuo deelif? for i in range(5):yi = 0; while i < 5: ...; i += 1hacen lo mismo. ¿En qué circunstancias tendrías que usarwhileporqueforgenuinamente no puede expresarlo?- La evaluación de cortocircuito significa que
a and bse salta la evaluación debsiaya esFalse. ¿Se te ocurre una situación (además del ejemplo de división entre cero de arriba) donde esto importe por algo más que rendimiento —donde evaluarbcuando no debería evaluarse en realidad sería incorrecto, no solo innecesario? - El ejemplo de la tabla de multiplicar anida un
fordentro de otrofor. ¿Cómo se vería anidar unwhiledentro de unfor, y se te ocurre una tarea real (no un ejemplo inventado) donde esa combinación sería la elección natural?