class: center, middle, inverse, title-slide .title[ # Loops-Bucles ] .subtitle[ ## MAD-UdelaR ] .author[ ### Daniel Miles Touya ] .date[ ### 2025-06-18 ] --- <style> .scroll-output { max-height: 300px; overflow-y: auto; background: #f9f9f9; border: 1px solid #ccc; padding: 10px; font-family: monospace; font-size: 70%; white-space: pre-wrap; } </style> # Bucles Los **bucles** permiten repetir instrucciones sin escribirlas muchas veces. ```python print("meow") print("meow") print("meow") ``` > ¿Y si quisiéramos imprimir `"meow"` 500 veces? >> Usamos **bucles** para automatizar repeticiones. --- # `while` loop básico .pull-left[ <b style="color:red">OJO</b> Este código **nunca se detiene**. ```python i = 3 while i ! = 0: print("meow") ``` Falta actualizar `i`. ] -- .pull-right[ Corrigiendo el bucle infinito ```python i = 3 while i ! = 0: print("meow") i = i - 1 ``` Cada **iteración** reduce `i` hasta que se vuelve 0. ] --- # Bucle .pull-left[ Mejorando el bucle `while` ```python i = 0 while i < 3: print("meow") i += 1 # i = i + 1 ``` ] -- .pull-right[ <img src="loop.png" height= "350px"> ] --- # Loops .pull-left[ Bucle `for` con listas ```python for i in [0, 1, 2]: print("meow") ``` Más compacto y fácil de leer. ] .pull-right[ Usando `range()` ```python for i in range(3): print("meow") ``` `range(3)` genera los valores `0, 1, 2` ] -- .pull-left[ Ignorar la variable del bucle ```python for _ in range(3): print("meow") ``` Se usa `_` si no necesitas el valor de `i`. ] -- .pull-right[ Otra forma: multiplicación de cadenas ```python print("meow" * 3) ``` Resultado: `meowmeowmeow` ] --- # `while True` con `break` Quebrar un bucle: `break`: ```python while True: n = int(input("¿Cuál es n? ")) if n > 0: break ``` > El bucle se repite al infinito **hasta que** se cumpla la condición. > `break`: quiebra el loop cuando se cumple la condición --- # `continue` (innecesario pero ilustrativo) ```python while True: n = int(input("¿Cuál es n? ")) if n < 0: continue break ``` > `continue` **salta al inicio** del bucle. > `break` **sale completamente** del bucle. --- # Comparando `continue` vs `break` .pull-left[ `Continue` como filtro ```python for i in range(5): if i == 2: continue print(i) ``` > Imprime: `0`, `1`, `3`, `4` > Salta el `2`, pero no rompe el bucle. ] -- .pull-right[ `Break`: sale del loop ```python for i in range(5): if i == 2: break print(i) ``` Imprime: `0`, `1` Detiene el bucle al llegar a `i == 2`. ] --- # Loops anidados Es posible meter un bucle dentro de otro .pull-left[ ````python for i in range(1, 4): for j in range(1, 3): print(f"i = {i}, j = {j}") ```` ] -- .pull-right[ ````python i = 1 while i <= 3: j = 1 while j <= 2: print(f"i = {i}, j = {j}") j += 1 i += 1 ```` ] --- # Loops anidados <b style="color:green">Ejercicio: Analizar este código</b> Cada usuario tiene hasta 3 intentos para ingresar la contraseña. Si deja la entrada vacía → no se cuenta como intento. Si falla 3 veces → se bloquea. <div style=" max-height: 300px; overflow-y: auto; background-color: #f8f8f8; border: 1px solid #ddd; padding: 10px; font-family: monospace; font-size: 0.85em; margin: auto 0; "> ```python usuarios = { "ana": "clave123", "luis": "python42", "marta": "abc321" } intentos_maximos = 3 for usuario in usuarios: print(f"\n▶ Iniciando sesión para {usuario}") intentos = 0 while intentos < intentos_maximos: clave = input(f"Ingresa la contraseña para {usuario}: ") if clave == usuarios[usuario]: print("✅ Acceso concedido.") break else: print("❌ Contraseña incorrecta.") intentos += 1 if intentos == 2: print("⚠️ Último intento...") if clave == "": print("⏭️ Entrada vacía ignorada.") continue else: print("⛔ Acceso bloqueado por intentos fallidos.") </div> --- Ejercicio: Estudiar este control de accesos a una plataroma ````python usuarios = { "ana": "clave123", "luis": "python42", "marta": "abc321" } intentos_maximos = 3 for usuario in usuarios: print(f"\n▶ Iniciando sesión para {usuario}") intentos = 0 while intentos < intentos_maximos: clave = input(f"Ingresa la contraseña para {usuario}: ") if clave == usuarios[usuario]: print(" Acceso concedido.") break # sale del while y pasa al siguiente usuario else: print(" Contraseña incorrecta.") intentos += 1 if intentos == 2: print(" Último intento...") if clave == "": print("️ Entrada vacía ignorada.") continue # no cuenta como intento si está vacío else: print(" Acceso bloqueado por intentos fallidos.") ```` --- # Loops: otras cuestiones ```python names = ['Nellie', 'Ronald', 'Judith', 'Lavonda'] # Mala práctica: usar índices for i in range(len(names)): print(names[i]) ``` -- Mejor práctica: `for-in` loop ```python for name in names: print(name) ``` El nombre de la variable (`name`) lo eliges tú. -- También válido: ```python for x in names: print(x) ``` --- # Loops: otras cuestiones Iterar con índice: `enumerate()` ```python colors = ["red", "green", "blue", "purple"] ratios = [0.2, 0.3, 0.1, 0.4] for i, color in enumerate(colors): print(f"{ratios[i] * 100}% {color}") ``` -- <b style="color:brown">Mejor aún: `zip()`</b> ```python for color, ratio in zip(colors, ratios): print(f"{ratio * 100}% {color}") ``` -- `zip()` une estructuras de datos de forma elegante y clara. La función `zip()` **combina múltiples iterables** (listas, tuplas, etc.) en **tuplas agrupadas** elemento a elemento. > "Empareja" los elementos por posición. --- # `zip` >Sintáxis ```python zip(iterable1, iterable2, ...) ``` Devuelve un **iterador** de tuplas. ```python nombres = ['Ana', 'Luis', 'Marta'] edades = [23, 31, 19] combinado = zip(nombres, edades) print(list(combinado)) ``` -- * Se detiene en la **longitud del iterable más corto**. * Puedes convertirlo en `list()`, `dict()`, etc. --- # `zip` > Convertir a un diccionario ```python # Cnvertir a diccionario claves = ['a', 'b', 'c'] valores = [1, 2, 3] d = dict(zip(claves, valores)) print(d) ``` -- >Usarlo en un bucle ```python nombres = ['Ana', 'Luis', 'Marta'] edades = [23, 31, 19] for nombre, edad in zip(nombres, edades): print(f"{nombre} tiene {edad} años") ``` --- # Loops: otras cuestiones Iterar sobre diccionarios .pull-left[ ```python animals = {'birds': 3, 'cats': 2, 'dogs': 1} for animal in animals: print(f"I have {animals[animal]} {animal}") ``` ] -- .pull-right[ Mejor: usar `.items()` ```python for animal, count in animals.items(): print(f"I have {count} {animal}") ``` ] .pull-right[ Esto se llama <b style="color:brown">tuple unpacking</b> También llamado iterable unpacking o multiple assignment ] --- # List-Dictionary Comprehension Un <b style="color:brown">comprehension</b> es una forma más corta y clara de construir listas-dictionarios a partir de otras listas o iterable ````python my_fav_numbers = [1, 1, 2, 3, 5, 8, 13] doubled = [] for n in my_fav_numbers: doubled.append(n * 2) ```` -- List comprehension ````python doubled = [n * 2 for n in my_fav_numbers] ```` --- # List-Dictionary Comprehension Una <b style="color:brown">dictionary comprehension</b> permite construir diccionarios de forma concisa. ```python words = ["apple", "banana", "cherry"] lengths = {} for word in words: lengths[word] = len(word) ``` -- Dctionary comprehension: ```python lengths = {word: len(word) for word in words} ``` -- ```python {clave: valor for elemento in iterable} ``` --- # List comprehensions Tuplas `\((x, x^2)\)` con `for` loop ```python squares = [] for x in range(1, 11): squares.append((x, x ** 2)) ``` Cuando tenemos un `append` claramente lo podemos transformar Readability ```python squares = [(x, x ** 2) for x in range(1, 11)] ``` --- # List comprehensions: nested comprehensions Queremos generar una tabla del 1 al 4, hasta el 6: .pull-left[ Tabla de multiplicar ``` [ [1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12], [4, 8, 12, 16], [5, 10, 15, 20], [6, 12, 18, 24] ] ``` ] -- .pull-right[ ```python table = [] for i in range(1, 7): # 6 filas row = [] for j in range(1, 5): # 4 columnas row.append(i * j) table.append(row) ``` Cada fila representa las multiplicaciones de un número `i` por los números del 1 al 4. ] -- .pull-right[ >List comprehension anidada ```python table = [[i * j for j in range(1, 5)] for i in range(1, 7)] ``` >Revierto el orden de iteración ] --- # List comprehensions: conditionals Extraer positivos .pull-left[ ````python nums = [4, -1, 9, 0, -4] new_nums = [] for n in nums: if n > 0: new_nums.append(n) ```` ] .pull-right[ ````python new_nums = [n for n in nums if n > 0] ```` ] -- .pull-left[ ````python from math import sqrt results = [] for n in range(101): if sqrt(n).is_integer(): results.append(n ** 3) ```` ] .pull-right[ ````python from math import sqrt results = [n ** 3 for n in range(101) if sqrt(n).is_integer()] ```` ] > Sintaxis `[expresión for elemento in iterable if condición]` --- # List comprehension `if-else ````python nums = [1, 2, 3, 4, 5] labels = [] for n in nums: if n % 2 == 0: labels.append("par") else: labels.append("impar") ```` ````python labels = ["par" if n % 2 == 0 else "impar" for n in nums] ```` Sintaxis `[valor_si_verdadero if condición else valor_si_falso for elemento in iterable]` --- # Dictrionary comprehension `if` Con bucle `for` y `if`: ```python num_pets = { 'cats': 6, 'dogs': 4, 'hamsters': 7, 'birds': 3 } too_many = {} for pet, num in num_pets.items(): if num > 4: too_many[pet] = num ``` ```python too_many = {pet: num for pet, num in num_pets.items() if num > 4} ``` Sintaxis: `{clave: valor for clave, valor in iterable if condición}` --- # Consejo de estilo: empieza con un `for` loop Es más claro y seguro comenzar con un bucle tradicional: ```python too_many = [] for pet, num in num_pets.items(): if num > 4: too_many.append(pet) ``` > Luego conviértelo a list comprehension ```python too_many = [ pet for pet, num in num_pets.items() if num > 4 ] ``` >Así te aseguras de entender bien la lógica **antes de condensarla**. --- # Consejo: rompe la comprehension en varias líneas - Mejora la **legibilidad** - Facilita el debugging -️ Ideal para condiciones complejas -- >No hagas esto con cosas complejas ```python # Demasiado denso: [n ** 2 for n in nums if n > 0 and n % 2 == 0 and n < 100] ``` > Mejor romper en varias líneas: ```python [ n ** 2 for n in nums if n > 0 and n % 2 == 0 and n < 100 ] ``` --- # Bucles Ejercicios 1-<a href="python_ejercicios_loops.html" target="_blank">Bucles</a> 2-<a href="python_ejercicios_comprehensions.html" target="_blank">Comprehensions</a>