Hola! Aquí empieza a ser un programa
Hasta ahora Python era una calculadora con memoria. Guardaba valores y hacía cuentas 🧮
Con este capítulo empieza a tomar decisiones y a repetir trabajo, que son las dos cosas por las que valió la pena aprenderlo.
La sangría, que aquí es sintaxis
Antes de nada, esto, porque es lo que más frustra la primera semana.
En otros lenguajes los bloques se marcan con llaves y la sangría es decoración. En Python la sangría es la que dice qué está dentro y qué está fuera. No es estética, es gramática.
monto = 1500
if monto > 1000:
print('Venta grande')
print('Se avisa al supervisor')
print('Esto sale siempre')
Venta grande Se avisa al supervisor Esto sale siempre
Los dos primeros print están dentro del if porque
tienen cuatro espacios. El tercero está fuera porque no los tiene. Cambia la
sangría y cambias el programa.
Las reglas que te evitan el 99% de los problemas:
- 📏 Cuatro espacios. Siempre cuatro, nunca dos ni ocho. Lo dice PEP 8 y lo respeta todo el mundo.
- 🚫 Nunca mezcles espacios con tabulaciones. Se ven igual y Python los cuenta distinto, así que produce errores imposibles de ver a ojo.
- ⌨️ Configura tu editor para que la tecla Tab inserte cuatro espacios. En Colab ya viene así.
if monto > 1000:
print('sin sangria')
IndentationError: expected an indented block after 'if' statement on line 1
if, elif, else
monto = 780
if monto > 2000:
categoria = 'Mayorista'
elif monto > 500:
categoria = 'Mediana'
elif monto > 100:
categoria = 'Pequeña'
else:
categoria = 'Mínima'
print(categoria)
Mediana
Se evalúan en orden y se sale en la primera que se cumple. Por eso 780 salió como Mediana y nunca llegó a preguntarse si era mayor que 100.
Ese detalle del orden es donde se cometen los errores de verdad. Mira qué pasa si lo escribes al revés:
if monto > 100:
categoria = 'Pequeña'
elif monto > 500:
categoria = 'Mediana'
elif monto > 2000:
categoria = 'Mayorista'
print(categoria)
Pequeña
Ahí ya nada puede ser Mediana ni Mayorista jamás, porque todo lo que pasa de 500 también pasa de 100 y se sale en la primera 😬
Con rangos, siempre de más estricto a menos estricto. Esto lo he visto arruinar segmentaciones enteras de clientes en empresas grandes, y no lo detecta ningún error: el código corre feliz.
Comparar y combinar
| Operador | Qué pregunta |
|---|---|
== | ¿son iguales? Ojo, dos signos |
!= | ¿son distintos? |
> < >= <= | mayor, menor, y sus versiones con igual |
in | ¿está dentro de esta lista o de este texto? |
and or not | combinar condiciones |
ciudad = 'Lima'
monto = 1500
canal = 'Web'
if ciudad in ['Lima', 'Callao'] and monto > 1000:
print('Reparto propio')
if canal != 'Tienda' or monto > 5000:
print('Necesita seguimiento')
print(100 < monto < 2000)
Reparto propio Necesita seguimiento True
Esa última línea es una gracia de Python que otros lenguajes no tienen: puedes encadenar comparaciones como en matemáticas. Se lee lindo 🌸
Y el error número uno de este capítulo:
if ciudad = 'Lima':
print('hola')
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
Un igual asigna, dos iguales comparan. Menos mal que Python te lo dice clarito.
El bucle for
Repite algo una vez por cada elemento de una lista.
ventas = [480.37, 154.83, 2480.84]
for v in ventas:
print(f'S/{v:,.2f}')
S/480.37 S/154.83 S/2,480.84
El nombre v lo eliges tú. Ponle uno que se entienda: si recorres
ciudades llámala ciudad, no x.
Cuando necesites números y no una lista, está range:
for i in range(5):
print(i, end=' ')
print()
for i in range(1, 4):
print(i, end=' ')
0 1 2 3 4 1 2 3
Igual que las rebanadas: el final no se incluye. Python es coherente con eso en todos lados, y una vez que lo interiorizas deja de sorprender.
enumerate, cuando necesitas la posición
La tentación es llevar un contador a mano. No hace falta:
ciudades = ['Lima', 'Arequipa', 'Cusco']
for i, ciudad in enumerate(ciudades, start=1):
print(f'{i}. {ciudad}')
1. Lima 2. Arequipa 3. Cusco
zip, para recorrer dos listas a la vez
ciudades = ['Lima', 'Arequipa', 'Cusco']
montos = [12500.5, 980.25, 145600.0]
for ciudad, monto in zip(ciudades, montos):
print(f'{ciudad:<10} S/{monto:>12,.2f}')
Lima S/ 12,500.50 Arequipa S/ 980.25 Cusco S/ 145,600.00
Cuidado con una cosa: zip se detiene en la lista más corta y no
te avisa. Si una tiene 100 elementos y la otra 98, procesas 98 y pierdes dos en
silencio 🤫
Acumular, que es para lo que más se usa
ventas = [480.37, 154.83, 2480.84, 524.90]
total = 0
mayores = 0
for v in ventas:
total = total + v
if v > 500:
mayores = mayores + 1
print(f'Total S/{total:,.2f} en {len(ventas)} ventas')
print(f'{mayores} pasaron los S/500')
Total S/3,640.94 en 4 ventas 2 pasaron los S/500
Fíjate en que total = 0 va antes del bucle. Si
lo pones dentro, se reinicia en cada vuelta y terminas con el último valor en vez
del total. Es un error clásico y silencioso.
El bucle while
for repite una vez por elemento. while repite
mientras una condición sea verdadera, y no sabe de antemano
cuántas veces va a ser.
saldo = 10000
meses = 0
while saldo > 0:
saldo = saldo - 1500
meses = meses + 1
print(f'Se acaba en {meses} meses, con saldo {saldo}')
Se acaba en 7 meses, con saldo -500
Y ahora la advertencia que todo el mundo necesita una vez en la vida:
# NO ejecutes esto
saldo = 10000
while saldo > 0:
print('sigo aqui')
Nada dentro del bucle cambia saldo, así que la condición nunca
deja de cumplirse. Eso es un bucle infinito y tu cuaderno se
queda colgado hasta que lo detengas 🔁
La regla: dentro de un while, algo tiene que mover la
condición. Si no lo ves a simple vista, revísalo antes de ejecutar.
En Colab se corta con el botón de stop de la celda, y si quedó muy trabado, Entorno de ejecución y después Reiniciar. No pasa nada, no rompiste nada.
break y continue
montos = [120.0, 340.5, -50.0, 890.0, 1200.0]
for m in montos:
if m < 0:
print('Monto negativo, algo esta mal en el archivo')
break
print(f'Procesando S/{m}')
Procesando S/120.0 Procesando S/340.5 Monto negativo, algo esta mal en el archivo
for m in montos:
if m < 0:
continue
print(f'Procesando S/{m}')
Procesando S/120.0 Procesando S/340.5 Procesando S/890.0 Procesando S/1200.0
break sale del bucle entero. continue se salta esa
vuelta y sigue con la siguiente. Los dos sirven, y elegir cuál depende de si el
dato raro es un aviso para parar o algo que simplemente se ignora.
Un caso completo
Vamos a juntar todo con algo que sí harías en el trabajo: clasificar ventas y sacar un resumen.
ventas = [
{'ciudad': 'Lima', 'monto': 2480.84, 'pagado': True},
{'ciudad': 'Cusco', 'monto': 154.83, 'pagado': False},
{'ciudad': 'Lima', 'monto': 780.0, 'pagado': True},
{'ciudad': 'Piura', 'monto': 95.5, 'pagado': False},
{'ciudad': 'Lima', 'monto': 3200.0, 'pagado': True},
]
cobrado = 0
por_cobrar = 0
categorias = {}
for v in ventas:
if v['pagado']:
cobrado = cobrado + v['monto']
else:
por_cobrar = por_cobrar + v['monto']
if v['monto'] > 2000:
cat = 'Mayorista'
elif v['monto'] > 500:
cat = 'Mediana'
else:
cat = 'Pequeña'
categorias[cat] = categorias.get(cat, 0) + 1
print(f'Cobrado S/{cobrado:,.2f}')
print(f'Por cobrar S/{por_cobrar:,.2f}')
print(categorias)
Cobrado S/6,460.84
Por cobrar S/250.33
{'Mayorista': 2, 'Pequeña': 2, 'Mediana': 1}
Treinta líneas y ya es un reporte que alguien podría pedirte. Con pandas van a ser cuatro, pero ahora entiendes qué está haciendo por dentro 💜
Ejercicios
1. Semáforo de stock
Dado un número de unidades, imprime "Crítico" si es menor a 10, "Bajo" si es menor a 50, y "OK" en el resto de casos.
unidades = 34
if unidades < 10:
print('Crítico')
elif unidades < 50:
print('Bajo')
else:
print('OK')
Bajo
Del más estricto al menos estricto. Si pones el < 50 primero,
nada será nunca Crítico.
2. Suma solo lo que corresponde
De una lista de montos, suma solo los positivos y cuenta cuántos negativos descartaste.
montos = [120.0, -50.0, 340.5, -12.0, 890.0]
total = 0
descartados = 0
for m in montos:
if m < 0:
descartados = descartados + 1
continue
total = total + m
print(f'Total S/{total:,.2f}, {descartados} descartados')
Total S/1,350.50, 2 descartados
Contar lo que descartas es tan importante como sumar lo que sirve. Si un día descartas la mitad del archivo, quieres enterarte.
3. Tabla numerada
Imprime una lista de ciudades numerada desde 1, alineando el número a la derecha en dos espacios.
ciudades = ['Lima', 'Arequipa', 'Cusco', 'Piura']
for i, c in enumerate(ciudades, start=1):
print(f'{i:>2}. {c}')
1. Lima 2. Arequipa 3. Cusco 4. Piura
4. Dos listas a la vez
Con una lista de productos y otra de stock, imprime solo los que tengan menos de 20 unidades.
productos = ['Abarrotes', 'Bebidas', 'Limpieza', 'Snacks']
stock = [45, 12, 8, 30]
for p, s in zip(productos, stock):
if s < 20:
print(f'{p}: quedan {s}')
Bebidas: quedan 12 Limpieza: quedan 8
5. Cuántos meses hasta la meta
Empiezas con S/5.000 y ahorras S/800 al mes. ¿Cuántos meses
hasta llegar a S/20.000? Usa while.
ahorro = 5000
meses = 0
while ahorro < 20000:
ahorro = ahorro + 800
meses = meses + 1
print(f'{meses} meses, terminas con S/{ahorro:,}')
19 meses, terminas con S/20,200
6. Parar en el primer problema
Recorre una lista de códigos de cliente y detente en cuanto encuentres uno vacío, avisando en qué posición estaba.
codigos = ['C0045', 'C0325', '', 'C0260']
for i, c in enumerate(codigos):
if c == '':
print(f'Código vacío en la posición {i}')
break
print(f'OK {c}')
OK C0045 OK C0325 Código vacío en la posición 2
7. El acumulador mal puesto
Escribe a propósito el error de inicializar el total dentro del bucle y explica el resultado.
ventas = [100, 200, 300]
for v in ventas:
total = 0 # mal: se reinicia cada vuelta
total = total + v
print(total)
300
Sale 300 y no 600, porque en la última vuelta el total volvió a cero y solo sumó el último valor. No hay error, hay un número equivocado, que es peor.
8. Filtrar por dos condiciones
De una lista de ventas, cuenta las que son de Lima y pasan de S/1.000.
ventas = [
{'ciudad': 'Lima', 'monto': 2480.84},
{'ciudad': 'Cusco', 'monto': 1540.0},
{'ciudad': 'Lima', 'monto': 780.0},
{'ciudad': 'Lima', 'monto': 3200.0},
]
cuenta = 0
for v in ventas:
if v['ciudad'] == 'Lima' and v['monto'] > 1000:
cuenta = cuenta + 1
print(cuenta)
2
9. La comparación encadenada
Clasifica un puntaje de satisfacción del 1 al 5 usando una comparación encadenada para validar que esté en rango.
puntaje = 4
if not 1 <= puntaje <= 5:
print('Puntaje fuera de rango')
elif puntaje >= 4:
print('Cliente satisfecho')
else:
print('Cliente en riesgo')
Cliente satisfecho
Validar el rango antes de clasificar es una costumbre que salva reportes. Un puntaje de 9 en una escala del 1 al 5 significa que alguien cargó mal los datos.
10. El bucle que se pasa
Un cliente debe S/3.000 y paga S/700 al mes. Muestra el saldo mes a mes hasta que quede en cero o negativo.
saldo = 3000
mes = 0
while saldo > 0:
mes = mes + 1
saldo = saldo - 700
print(f'Mes {mes}: quedan S/{saldo}')
Mes 1: quedan S/2300 Mes 2: quedan S/1600 Mes 3: quedan S/900 Mes 4: quedan S/200 Mes 5: quedan S/-500
El último mes se pasa. En un caso real ahí pondrías
min(700, saldo) para cobrar solo lo que falta, que es exactamente el
tipo de detalle que diferencia un cálculo correcto de uno que casi lo es.
Lo que te llevas
- 📏 La sangría es sintaxis: cuatro espacios, sin mezclar con tabulaciones.
- 🪜 En una cadena de
elifcon rangos, siempre del más estricto al menos estricto. - 🔢 En
rangey en las rebanadas, el final no se incluye. - ➕ El acumulador se inicializa antes del bucle.
- ♾️ En un
while, algo dentro tiene que mover la condición.
En el capítulo 5 vamos a empaquetar todo esto en funciones, que es lo que hace que dejes de copiar y pegar el mismo bloque en cinco sitios.
Que tengas lindo día! 🌸