Condicionales en Python — práctica con un validador de registro, descuentos por nivel y un clasificador de notas (y el formulario que solo te enseñaba un error)
La semana que empecé con los condicionales me registré en la web de un gimnasio. Escribí un usuario de dos letras y una contraseña cortita, y la web me dijo: «El usuario debe tener al menos 3 caracteres». Lo arreglé y volví a enviar. «La contraseña debe tener al menos 6 caracteres». Lo arreglé. «La contraseña debe contener un número». Tres envíos para descubrir tres errores que la web conocía desde el primero. Esa noche, haciendo la práctica de FP1, me di cuenta de que mi validador hacía exactamente lo mismo, y de por qué: estaba todo metido en una sola cadena de elif.
Esa es la lección que recorre esta práctica: una cadena if/elif elige un camino; varios if seguidos revisan varias cosas. Saber cuál toca en cada momento es la mitad de programar con condicionales.
Esta es la práctica de la teoría de condicionales en Python. Vamos a escribir tres programas completos, de nivel medio, con if, elif, else, and, or y el ternario: un validador de formulario de registro, un sistema de descuentos por nivel de cliente y un clasificador de notas con menú. Los datos van fijos en variables en lugar de input(), para que puedas ejecutar cada programa y obtener exactamente la misma salida que aquí; además, los datos están elegidos para que se parezcan a los de verdad: un usuario demasiado corto, un email sin punto, un cliente que se queda a un céntimo de subir de nivel… Cuando lo tengas claro, cambia cada variable por un input() y tendrás la versión interactiva.
Tabla de Contenidos
Antes de empezar
Conviene tener claro:
- Que en una cadena
if/elif/elsesolo se ejecuta el bloque del primerTrue. - Cómo se combinan condiciones con
and,orynot, y que0 <= nota <= 10comprueba un rango. - Que
input()siempre devuelve texto (por eso las opciones del menú se comparan con"1"y no con1). - El operador ternario:
"error" if n == 1 else "errores".
Si alguno te suena dudoso, repasa la teoría antes de seguir.
Crea una carpeta practica_condicionales y un archivo por programa (validador.py, descuentos.py, clasificador.py). En VS Code, ejecútalos con el botón de ejecutar (el triángulo de arriba a la derecha) o con python3 validador.py en la terminal integrada. Así puedes cambiar un dato y volver a ejecutar en dos segundos.
Programa 1: validador de formulario de registro
Cualquier web comprueba tus datos antes de crearte una cuenta. Nuestro validador recibe cuatro datos (usuario, edad, contraseña y email) y tiene que decir qué está bien y qué está mal. Lo que lo complica: hay que decidir si paramos en el primer error o los revisamos todos, y la contraseña tiene dos requisitos que dependen uno del otro.
La idea
Empezamos por la versión ingenua, la de la web del gimnasio: una sola cadena if/elif. Después la convertimos en un if independiente por campo, con un contador errores que cada fallo incrementa. Dentro del campo de la contraseña sí usamos elif, porque ahí los dos requisitos están encadenados: si la contraseña es demasiado corta, no tiene sentido quejarse además de que le falta un número.
Antes de programar, piensa en esto para cada comprobación: ¿los casos se excluyen entre sí (uno u otro) o son independientes (uno, otro, los dos o ninguno)? Excluyentes → elif. Independientes → if separados.
El código
Primero, la versión 1, la de una sola cadena:
# Validador de registro — versión 1: una sola cadena if/elif
usuario = "Jo"
edad = 20
contrasena = "abc"
email = "sergio@sergiolearns.com"
print("=== REGISTRO DE USUARIO ===")
if len(usuario) < 3: # la primera condición True...
print("Error: el usuario debe tener al menos 3 caracteres")
elif edad < 18: # ...corta la cadena: el resto no se mira
print("Error: tienes que tener al menos 18 años")
elif len(contrasena) < 6:
print("Error: la contraseña debe tener al menos 6 caracteres")
elif "@" not in email or "." not in email:
print("Error: el email no es válido")
else: # solo si NINGUNA fue True
print("Registro completado con éxito")
Con el usuario "Jo" y la contraseña "abc" (dos errores), la salida es:
=== REGISTRO DE USUARIO === Error: el usuario debe tener al menos 3 caracteres
Solo un mensaje. La primera condición, len(usuario) < 3, da True (len("Jo") es 2), Python ejecuta su bloque y sale de la cadena. La contraseña corta está ahí, pero nadie la mira. Es el comportamiento correcto de un elif… y justo lo que no queremos en un formulario.
Ahora la versión 2, con un if por campo:
# Validador de registro — versión 2: un if independiente por campo
usuario = "Jo"
edad = 20
contrasena = "abc"
email = "sergio@sergiolearns.com"
errores = 0 # cada comprobación que falle suma 1
print("=== REGISTRO DE USUARIO ===")
# 1. Usuario: al menos 3 caracteres
if len(usuario) < 3:
print("✗ Usuario demasiado corto (mínimo 3 caracteres)")
errores += 1
else:
print("✓ Usuario válido")
# 2. Edad: 18 o más (por eso < 18 y no <= 18)
if edad < 18:
print("✗ Tienes que tener al menos 18 años")
errores += 1
else:
print("✓ Edad válida")
# 3. Contraseña: primero la longitud; el número solo se mira si la longitud está bien
if len(contrasena) < 6:
print("✗ Contraseña demasiado corta (mínimo 6 caracteres)")
errores += 1
elif not any(c.isdigit() for c in contrasena): # ¿algún carácter es un dígito?
print("✗ La contraseña necesita al menos un número")
errores += 1
else:
print("✓ Contraseña válida")
# 4. Email: falla si le falta la @ O le falta el punto
if "@" not in email or "." not in email:
print("✗ Email no válido")
errores += 1
else:
print("✓ Email válido")
# Resumen: el ternario elige entre "error" y "errores"
if errores == 0:
print("Registro completado")
else:
palabra = "error" if errores == 1 else "errores"
print(f"Registro fallido: {errores} {palabra}")
Salida
Con los mismos datos:
=== REGISTRO DE USUARIO === ✗ Usuario demasiado corto (mínimo 3 caracteres) ✓ Edad válida ✗ Contraseña demasiado corta (mínimo 6 caracteres) ✓ Email válido Registro fallido: 2 errores
Ahora salen los dos fallos de una vez. Comprobación a mano: len("Jo") = 2 < 3 → no y errores pasa a 1; 20 < 18 es False → sí; len("abc") = 3 < 6 → no y errores pasa a 2 (el elif del número ni se mira, porque la longitud ya ha fallado); el email tiene @ y . → sí. Total: 2, y como no es 1, el ternario elige «errores».
He ejecutado el mismo programa con otros datos (archivo validador_laura.py): usuario "laura_g", 19 años, contraseña "pythonfp" y email "laura@gmailcom". La salida real:
=== REGISTRO DE USUARIO === ✓ Usuario válido ✓ Edad válida ✗ La contraseña necesita al menos un número ✗ Email no válido Registro fallido: 2 errores
Aquí se ve el otro camino de la contraseña: tiene 8 caracteres, así que pasa el if de la longitud y llega al elif, donde any(...) no encuentra ningún dígito. Y el email tiene @ pero no tiene ., así que "." not in email es True y basta para que el or dé True.
La diferencia entre las dos versiones se ve de un vistazo en este dibujo:
Vamos con la parte más difícil, la contraseña, otra vez y por separado:
# 3. Contraseña: primero la longitud; el número solo se mira si la longitud está bien
if len(contrasena) < 6:
print("✗ Contraseña demasiado corta (mínimo 6 caracteres)")
errores += 1
elif not any(c.isdigit() for c in contrasena): # ¿algún carácter es un dígito?
print("✗ La contraseña necesita al menos un número")
errores += 1
else:
print("✓ Contraseña válida")
any(c.isdigit() for c in contrasena) se lee «¿algún carácter c de la contraseña es un dígito?». Recorre la contraseña carácter a carácter y devuelve True en cuanto encuentra uno. Por dentro es un pequeño bucle (lo verás a fondo en el próximo tema); de momento quédate con que responde sí o no. El not le da la vuelta: «no hay ningún dígito».
| Contraseña | len(...) < 6 | ¿Llega al elif? | not any(dígito) | Mensaje |
|---|---|---|---|---|
"abc" | 3 < 6 → True | No | — | Demasiado corta |
"pythonfp" | 8 < 6 → False | Sí | True (no hay dígitos) | Necesita un número |
"fp1python" | 9 < 6 → False | Sí | False (está el 1) | Contraseña válida |
Preguntas que te puedes hacer
¿Por qué edad < 18 y no edad <= 18? Porque con 18 años ya puedes registrarte. edad < 18 solo marca error de 17 hacia abajo. Con <=, un usuario de 18 recién cumplidos recibiría un error injusto. Cada vez que escribas un límite, pruébalo con el valor exacto del límite.
¿Por qué en el email es or y no and? Porque el email es inválido si le falta la @ o le falta el punto: con que falte uno ya está mal. Con and, solo daría error cuando faltaran los dos, y "laura@gmailcom" pasaría como válido. Es la versión «en negativo» de «tiene que tener @ y punto».
¿Por qué el contador y no un booleano todo_ok? Un booleano te diría si hay algún error; el contador te dice cuántos, y el mensaje final queda más útil. Además, errores == 0 es exactamente la condición de «todo bien».
¿Por qué el ternario solo en el else? Porque «error»/«errores» solo tiene sentido cuando hay errores. Si errores vale 0, el programa ya ha impreso «Registro completado» y no necesita la palabra.
¿Comprobar "@" in email basta para validar un email de verdad? No: "@." pasaría. Las webs reales usan expresiones regulares o mandan un correo de confirmación. Para FP1, esta comprobación sirve para practicar in, not in y or.
Escribir el validador como una cadena de elif y pensar que «funciona» porque con datos correctos dice «Registro completado». El fallo solo se ve cuando hay dos o más errores a la vez. Prueba siempre con un caso que tenga varios.
Pruébalo tú
- Añade un quinto campo, «repetir contraseña», y marca error si no coincide con la primera (
!=). - Cambia el mensaje final para que, si solo hay un error, diga cuál ha sido en lugar de «1 error» (pista: guarda el texto del último error en una variable).
Programa 2: sistema de descuentos por nivel de cliente
Una tienda clasifica a sus clientes por lo que gastan al año: Básico, Silver, Gold y Platinum, cada nivel con su descuento. Los socios tienen un 5 % extra en cualquier nivel. El programa calcula el nivel, el descuento total, el ahorro y lo que pagaría, y termina con un mensaje según el nivel. Lo complicado: elegir bien el orden de los umbrales, decidir qué va en la cadena y qué va aparte, y no fallar justo en los límites (500 € exactos, ¿Básico o Silver?).
La idea
Es el patrón que más usarás en FP1: una cadena if/elif/else que no imprime nada, solo asigna valores a variables (nivel y descuento); el resto del programa trabaja con esas variables. El extra de socio va en un if separado, porque no es otro nivel: se suma al que haya. Y el mensaje final compara nivel, no el dinero, para no repetir los umbrales en dos sitios.
Antes de programar, dibuja los tramos en una recta y decide a qué lado cae cada límite. Si el enunciado dice «a partir de 500 €», el 500 es Silver: eso es un >=.
El código
# Sistema de descuentos por nivel de cliente
nombre = "Laura"
gasto_anual = 2500.0
respuesta_socio = "S" # como si viniera de input(): un texto
es_socio = respuesta_socio.lower() == "s" # "S" → "s" → True (acepta s y S)
# 1. Nivel y descuento base: de mayor a menor, gana el primer umbral que se cumple
if gasto_anual >= 5000:
nivel = "Platinum"
descuento = 20
elif gasto_anual >= 2000: # aquí ya sabemos que gasto_anual < 5000
nivel = "Gold"
descuento = 15
elif gasto_anual >= 500:
nivel = "Silver"
descuento = 10
else:
nivel = "Básico"
descuento = 5
# 2. Extra por ser socio: if aparte, porque se suma a CUALQUIER nivel
if es_socio:
descuento_extra = 5
else:
descuento_extra = 0
descuento_total = descuento + descuento_extra
# 3. Cuentas
ahorro = gasto_anual * descuento_total / 100
pagaria = gasto_anual - ahorro
print(f"--- Ficha de {nombre} ---")
print(f"Gasto anual: {gasto_anual:.2f} €")
print(f"Nivel: {nivel} (descuento base {descuento} %)")
if es_socio: # esta línea solo sale para los socios
print(f"Descuento socio: +{descuento_extra} %")
print(f"Descuento total: {descuento_total} %")
print(f"Ahorro: {ahorro:.2f} €")
print(f"Pagaría: {pagaria:.2f} €")
# 4. Mensaje según el nivel ya calculado (no se repiten las comparaciones de dinero)
if nivel == "Platinum":
print("⭐ Platinum: acceso a eventos exclusivos")
elif nivel == "Gold":
print("🥇 Gold: envío gratuito en todos los pedidos")
elif nivel == "Silver":
print("🥈 Silver: acceso anticipado a rebajas")
else:
falta = 500 - gasto_anual
print(f"ℹ️ Te faltan {falta:.2f} € para subir a Silver")
Salida
Con Laura, que gasta 2.500 € al año y es socia:
--- Ficha de Laura --- Gasto anual: 2500.00 € Nivel: Gold (descuento base 15 %) Descuento socio: +5 % Descuento total: 20 % Ahorro: 500.00 € Pagaría: 2000.00 € 🥇 Gold: envío gratuito en todos los pedidos
Comprobación a mano: 2500 >= 5000 es False; 2500 >= 2000 es True → Gold, 15 %. Es socia → +5 %, total 20 %. Ahorro: 2500 × 20 / 100 = 500. Pagaría: 2500 − 500 = 2000. Todo cuadra.
Y ahora los límites, que es donde fallan los programas. Pablo gasta exactamente 500 € y no es socio (archivo descuentos_500.py):
--- Ficha de Pablo --- Gasto anual: 500.00 € Nivel: Silver (descuento base 10 %) Descuento total: 10 % Ahorro: 50.00 € Pagaría: 450.00 € 🥈 Silver: acceso anticipado a rebajas
Con 500 €, 500 >= 500 es True: Silver. Y si gastara un céntimo menos, 499,99 € (archivo descuentos_499.py):
--- Ficha de Pablo --- Gasto anual: 499.99 € Nivel: Básico (descuento base 5 %) Descuento total: 5 % Ahorro: 25.00 € Pagaría: 474.99 € ℹ️ Te faltan 0.01 € para subir a Silver
Aquí todas las condiciones dan False y entra en el else: Básico con un 5 %. Fíjate en las cuentas: 499.99 × 5 / 100 = 24.9995, que con dos decimales (:.2f) se redondea a 25.00; y 499.99 − 24.9995 = 474.9905, que se queda en 474.99. Por eso los importes se imprimen con :.2f: con dinero siempre quieres dos decimales, y sin formato verías colas como 24.999499999999998. Tampoco aparece la línea «Descuento socio», porque ese print está dentro de un if es_socio:.
El dibujo coloca a los tres clientes en sus tramos:
Vamos a la línea más curiosa del programa:
Se lee de derecha a izquierda: respuesta_socio.lower() convierte "S" en "s", después == "s" compara y da True, y ese True se guarda en es_socio. Una sola comparación acepta «s» y «S», y evita la trampa de respuesta == "s" or "S" que viste en la teoría.
| Paso | Expresión | Valor |
|---|---|---|
| 1 | respuesta_socio | "S" |
| 2 | respuesta_socio.lower() | "s" |
| 3 | "s" == "s" | True |
| 4 | es_socio | True |
Preguntas que te puedes hacer
¿Por qué los umbrales van de mayor a menor? Porque usamos >=. Si gasto_anual >= 500 fuera la primera condición, Laura (2.500 €) entraría ahí y se quedaría en Silver: el error del 9,2 de la teoría, pero con dinero. Con >=, siempre de la condición más exigente a la menos exigente.
¿Por qué no elif gasto_anual >= 2000 and gasto_anual < 5000? Porque si Python llega a ese elif, ya sabe que la condición de arriba (>= 5000) ha fallado. La segunda mitad está garantizada; escribirla solo añade una oportunidad de equivocarte en un número.
¿Por qué el extra de socio no es un elif más? Porque no es excluyente con los niveles: un cliente Gold puede ser socio y uno Básico también. Si fuera un elif de la cadena, solo se aplicaría cuando no se cumpliera ningún nivel. Independiente → if aparte.
¿Por qué el mensaje final compara nivel y no el dinero? Para que los umbrales estén escritos en un único sitio. Si mañana Silver empieza en 600 €, cambias una línea y el mensaje sigue cuadrando solo.
El límite. «A partir de 500 €» es >= 500, no > 500. Con >, Pablo y sus 500 € exactos se quedarían en Básico. Prueba siempre el valor exacto de cada umbral y el de justo debajo.
Cuando una cadena if/elif solo asigna variables, alinea las asignaciones como aquí (nivel y descuento en cada rama). Si te falta una variable en alguna rama, se ve de un vistazo… y te ahorras el NameError de usarla después sin haberla creado.
Pruébalo tú
- Añade un nivel Diamond a partir de 10.000 € con un 25 %. ¿En qué posición de la cadena tiene que ir?
- Haz que el extra de socio dependa del nivel: +5 % en Básico y Silver, +3 % en Gold y Platinum (pista: un ternario o un
ifconor).
Programa 3: clasificador de notas con menú
El más completo de los tres, y el que usa el ejemplo guía del tema: las notas de FP1. Un menú ofrece tres opciones (clasificar una nota, comparar dos notas y calcular qué nota necesitas en el examen) y el programa hace una cosa u otra según la opción elegida. Lo complicado: hay condicionales dentro de condicionales, hay que descartar las notas imposibles antes de clasificarlas y la opción 3 tiene tres desenlaces según una cuenta.
La idea
La estructura exterior es una cadena if opcion == "1" / elif "2" / elif "3" / else: las opciones se excluyen entre sí y el else recoge cualquier cosa no válida. Dentro de cada opción va su propia lógica. En la opción 1, la primera pregunta es «¿la nota es posible?»; solo si lo es, se clasifica. Así la cadena de calificaciones nunca recibe un 12 ni un −3.
Para la opción 3 usamos una regla de evaluación de ejemplo, la misma del Python Tutor de la teoría: nota final = 40 % prácticas + 60 % examen, y en el examen hay que sacar al menos un 4. Despejando, la nota que necesitas en el examen para llegar al 5 es (5 − 0.4 × prácticas) / 0.6.
Antes de programar, piensa en esto: las opciones del menú llegarían de input(), y input() devuelve texto. Por eso se compara con "1" y no con 1. Si comparas un texto con un número, "1" == 1 es simplemente False, sin error, y el menú nunca entraría en ninguna opción.
El código
# Clasificador de notas con menú
opcion = "1" # lo que se elegiría en el menú (input() devuelve texto)
nota = 6.5 # dato de la opción 1
nota1 = 6.5 # datos de la opción 2
nota2 = 8.0
nota_practicas = 5.5 # dato de la opción 3
print("=== CLASIFICADOR DE NOTAS ===")
print("1. Clasificar una nota")
print("2. Comparar dos notas")
print("3. ¿Qué necesito en el examen?")
print(f"Opción elegida: {opcion}")
if opcion == "1":
# Primero se descarta lo imposible: la cadena de abajo solo ve notas válidas
if not 0 <= nota <= 10:
print("Error: la nota debe estar entre 0 y 10")
else:
if nota >= 9:
calificacion = "Sobresaliente"
elif nota >= 7:
calificacion = "Notable"
elif nota >= 5:
calificacion = "Aprobado"
else:
calificacion = "Suspenso"
print(f"Nota {nota}: {calificacion}")
if nota < 5:
print(f"Te faltan {5 - nota:.1f} puntos para aprobar")
else:
print(f"Tienes {nota - 5:.1f} puntos sobre el aprobado")
elif opcion == "2":
if nota1 > nota2:
print(f"La nota 1 ({nota1}) gana por {nota1 - nota2:.1f} puntos")
elif nota2 > nota1:
print(f"La nota 2 ({nota2}) gana por {nota2 - nota1:.1f} puntos")
else: # ni mayor ni menor: iguales
print(f"Empate: las dos son {nota1}")
media = (nota1 + nota2) / 2
print(f"Media: {media:.2f} ({'Aprobado' if media >= 5 else 'Suspenso'})")
elif opcion == "3":
# Regla del ejemplo: final = 40 % prácticas + 60 % examen, y el examen pide un 4
necesaria = (5 - 0.4 * nota_practicas) / 0.6
if necesaria > 10:
print("Ni con un 10 en el examen llegas al 5: toca recuperar prácticas")
elif necesaria <= 4:
print("Con el 4 mínimo del examen ya apruebas")
else:
print(f"Necesitas al menos un {necesaria:.2f} en el examen")
else: # cualquier otro texto
print("Opción no válida: elige 1, 2 o 3")
Salida
Con opcion = "1" y una nota de 6.5:
=== CLASIFICADOR DE NOTAS === 1. Clasificar una nota 2. Comparar dos notas 3. ¿Qué necesito en el examen? Opción elegida: 1 Nota 6.5: Aprobado Tienes 1.5 puntos sobre el aprobado
0 <= 6.5 <= 10 es True, así que not lo convierte en False y entra en el else. Allí, 6.5 >= 9 y 6.5 >= 7 fallan, 6.5 >= 5 acierta: Aprobado. Y como 6.5 < 5 es False, imprime los puntos sobre el aprobado: 6.5 − 5 = 1.5.
Para ver las otras ramas he ejecutado el mismo programa cambiando solo la primera línea. Con opcion = "2" (notas 6.5 y 8.0):
=== CLASIFICADOR DE NOTAS === 1. Clasificar una nota 2. Comparar dos notas 3. ¿Qué necesito en el examen? Opción elegida: 2 La nota 2 (8.0) gana por 1.5 puntos Media: 7.25 (Aprobado)
6.5 > 8.0 es False; 8.0 > 6.5 es True → gana la nota 2 por 8.0 − 6.5 = 1.5. Media: (6.5 + 8.0) / 2 = 7.25, y el ternario dice «Aprobado» porque 7.25 >= 5.
Con opcion = "3" y un 5.5 en prácticas:
=== CLASIFICADOR DE NOTAS === 1. Clasificar una nota 2. Comparar dos notas 3. ¿Qué necesito en el examen? Opción elegida: 3 Necesitas al menos un 4.67 en el examen
Y con una opción que no existe, opcion = "7":
=== CLASIFICADOR DE NOTAS === 1. Clasificar una nota 2. Comparar dos notas 3. ¿Qué necesito en el examen? Opción elegida: 7 Opción no válida: elige 1, 2 o 3
Ninguna de las tres comparaciones da True, así que el programa cae en el else final. Sin ese else, una opción inválida no imprimiría nada y el usuario no sabría qué ha pasado.
La opción 3 merece un zoom:
elif opcion == "3":
# Regla del ejemplo: final = 40 % prácticas + 60 % examen, y el examen pide un 4
necesaria = (5 - 0.4 * nota_practicas) / 0.6
if necesaria > 10:
print("Ni con un 10 en el examen llegas al 5: toca recuperar prácticas")
elif necesaria <= 4:
print("Con el 4 mínimo del examen ya apruebas")
else:
print(f"Necesitas al menos un {necesaria:.2f} en el examen")
La cuenta: 0.4 × 5.5 = 2.2; 5 − 2.2 = 2.8; 2.8 / 0.6 = 4.666…, que con :.2f se imprime 4.67. Después, tres casos que se excluyen, y de nuevo el orden importa: primero lo imposible (más de 10), después lo que ya está cubierto por el 4 mínimo y, en el else, todo lo demás.
| Prácticas | Cuenta | necesaria | Rama | Mensaje |
|---|---|---|---|---|
| 5.5 | (5 − 2.2) / 0.6 | 4.67 | else | Necesitas al menos un 4.67 |
| 9.5 | (5 − 3.8) / 0.6 | ≈ 2 (1.9999999999999996) | elif necesaria <= 4 | Con el 4 mínimo ya apruebas |
| 0 | (5 − 0) / 0.6 | 8.33 | else | Necesitas al menos un 8.33 |
(La fila del 5.5 es la salida real de arriba; las otras dos son las cuentas a mano para que veas a qué rama iría cada caso.) El dibujo marca las tres zonas:
¿Por qué necesaria <= 4 da «con el 4 mínimo ya apruebas»? Porque aunque la cuenta diga que te bastaría un 2, la regla exige un 4 en el examen igualmente. Esa rama existe para no decirle a nadie «necesitas un 2.00» cuando con un 2 suspendería por no llegar al mínimo.
Preguntas que te puedes hacer
¿Por qué if not 0 <= nota <= 10 y no if nota < 0 or nota > 10? Las dos funcionan (son equivalentes por las leyes de De Morgan). La primera se lee como «si la nota no está en el rango», que es justo lo que queremos decir. Lo que no funcionaría es nota < 0 and nota > 10: ningún número es a la vez menor que 0 y mayor que 10, así que nunca daría error.
¿Por qué hay un if dentro del else de la opción 1? Porque «¿te falta para aprobar o vas sobrado?» solo tiene sentido con una nota válida. Es un anidamiento con motivo: la pregunta interior depende de la exterior.
¿Por qué {5 - nota:.1f}? Para que una resta como 5 − 4.3 (que en el ordenador da 0.7000000000000002) se imprima 0.7. El formato redondea solo al mostrar; el valor de la variable no cambia.
¿Por qué el empate es un else y no un elif nota1 == nota2? Porque si no es mayor ni menor, solo puede ser igual. Un elif con la condición escrita funcionaría igual, pero el else deja claro que no hay un cuarto caso posible.
¿Y si el usuario escribe " 1" con un espacio? Con input(), eso pasa más de lo que crees. " 1" == "1" es False, así que caería en «Opción no válida». La solución es limpiar el texto al leerlo: input(...).strip().
Comparar la opción con un número (if opcion == 1:) cuando viene de input(). No da error: simplemente nunca es igual, y el programa siempre dice «Opción no válida». Si un menú «ignora» todas las opciones, mira primero los tipos.
Pruébalo tú
- Añade una opción 4 que diga si una nota es «matrícula de honor» (10) usando
==, y comprueba que la opción 7 sigue cayendo en elelse. - En la opción 3, comprueba antes de calcular que
nota_practicasestá entre 0 y 10, igual que en la opción 1.
El patrón que más usarás en FP1
Si te quedas con una sola cosa de esta práctica, que sea esta: clasificar con una cadena if/elif/else que solo asigna, y usar la variable después. Lo has visto en los descuentos (nivel, descuento) y en las calificaciones (calificacion). Esta es su forma general, con el ejemplo de las notas:
if nota >= 9: # umbral más exigente primero (con >=)
categoria = "Sobresaliente"
elif nota >= 7: # aquí ya sabemos que nota < 9
categoria = "Notable"
elif nota >= 5:
categoria = "Aprobado"
else: # todo lo que no ha entrado arriba
categoria = "Suspenso"
print(f"Categoría: {categoria}") # la variable se usa DESPUÉS de la cadena
Es la misma plantilla para temperaturas (frío, templado, calor), edades (niño, adolescente, adulto), precios por tramos o niveles de batería. Tres cosas que no fallan: el else al final para que la variable exista siempre, los umbrales en orden y nada de repetir en un elif lo que ya garantiza el de arriba.
Errores típicos en esta práctica
- Usar una cadena
elifpara comprobaciones independientes. El validador solo informa del primer fallo. Independientes → variosif. - Umbrales en el orden equivocado. Con
>=, de mayor a menor; si no, las ramas altas son inalcanzables. - Fallar en el límite exacto. «A partir de 500» es
>= 500. Prueba siempre el valor del límite y el de justo debajo. anddonde ibaor(y al revés). «El email está mal si falta la@o falta el punto» llevaor; conandcasi todo pasa.- Comparar la opción del menú con un número.
input()devuelve texto: compara con"1". - Una variable que solo se crea en algunas ramas. Si una rama no asigna
descuentoy luego lo usas,NameError. Asigna en todas las ramas o dale un valor antes de la cadena.
Míralo paso a paso en Python Tutor
En pythontutor.com puedes ver el programa de descuentos ejecutándose línea a línea, con el valor de cada variable en cada momento. Elige Python 3 y pega esta versión reducida (sin los print de la ficha):
gasto_anual = 2500.0
es_socio = True
if gasto_anual >= 5000:
nivel = "Platinum"
descuento = 20
elif gasto_anual >= 2000:
nivel = "Gold"
descuento = 15
elif gasto_anual >= 500:
nivel = "Silver"
descuento = 10
else:
nivel = "Básico"
descuento = 5
if es_socio:
descuento = descuento + 5
pagaria = gasto_anual - gasto_anual * descuento / 100
print(nivel, descuento, pagaria)
Al final debería salir:
Gold 20 2000.0
Qué observar paso a paso:
- En la primera comparación (
gasto_anual >= 5000), la flecha no entra en el bloque de Platinum: salta directamente alelifsiguiente. - En
elif gasto_anual >= 2000, la flecha sí entra: aparecen en el panelnivel = "Gold"ydescuento = 15. Después salta por encima de Silver y delelsesin tocarlos. - En
if es_socio:, mira cómodescuentopasa de 15 a 20 en el panel: la misma variable cambia de valor, no se crea otra. - Al calcular
pagaria, comprueba la cuenta en el panel:2500 − 2500 × 20 / 100 = 2000.0. Cambiaes_socioaFalsey vuelve a ejecutar: verás que el bloque del socio se salta y el resultado pasa a2125.0.
Resumen
- Una cadena
if/elif/elseelige un solo camino; variosifseguidos revisan varias cosas. El validador de registro necesita lo segundo. - Con
>=, los umbrales van de mayor a menor; al llegar a unelif, todo lo de arriba ya esFalsey no hace falta volver a comprobarlo. - El patrón de FP1: la cadena solo asigna (
nivel,descuento,calificacion) y el resto del programa usa esas variables. - Los límites son donde fallan los programas: 500 € exactos es Silver, 499,99 € todavía no.
input()devuelve texto: las opciones de un menú se comparan con"1", y.lower()resuelve lo de «s» o «S».- Primero se descartan los datos imposibles (
if not 0 <= nota <= 10) y después se clasifica lo que queda.
Checklist: ¿lo has practicado?
- ¿Has ejecutado los tres programas y comprobado las salidas?
- ¿Sabes explicar por qué la versión 1 del validador solo enseña un error?
- ¿Has probado los descuentos con 500 € exactos y con 499,99 €?
- ¿Puedes decir, sin ejecutar, qué imprime el clasificador con
opcion = "3"y un 9.5 en prácticas? - ¿Has intentado los «Pruébalo tú» sin mirar la teoría?
- ¿Has cambiado algún dato por un
input()y has comprobado que sigue funcionando?
Si has respondido que sí a casi todo, estás listo para los ejercicios de condicionales en Python, donde ya no te doy el código hecho. ¡Nos vemos allí! Y si quieres repasar algo de base, la teoría de condicionales y los operadores en Python siguen ahí; el tema siguiente de la cadena son los bucles en Python.
Siguiente paso: ejerciciosCondicionales en Python — ejercicios resueltos con películas, tramos de impuestos, contraseñas y el juego de adivinar el número (y el or que dejaba entrar a todo el mundo)¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




Qué es un sistema operativo — teoría con tu portátil en una tarde de estudio, una llamada a write() y la CPU que nunca descansa (y los tres programas que no se ejecutaban a la vez)