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.

Antes de empezar

Conviene tener claro:

  • Que en una cadena if/elif/else solo se ejecuta el bloque del primer True.
  • Cómo se combinan condiciones con and, or y not, y que 0 <= nota <= 10 comprueba un rango.
  • Que input() siempre devuelve texto (por eso las opciones del menú se comparan con "1" y no con 1).
  • 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:

Cadena elif frente a un if por campoPara el usuario Jo, la cadena if/elif solo informa del usuario corto y no mira el resto; la versión con un if por campo revisa los cuatro y cuenta dos errores.Versión 1: una cadena if/elifusuario "Jo"  corto: se para aquíedad 20no se miracontraseña "abc"no se miraemailno se mira1 mensaje de errorVersión 2: un if por campousuario "Jo"  demasiado cortoedad 20  válidacontraseña "abc"  demasiado cortaemail  válidoerrores = 2
La cadena elif se detiene en el primer fallo; con un if por campo se revisan los cuatro y el contador llega a 2.

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ñalen(...) < 6¿Llega al elif?not any(dígito)Mensaje
"abc"3 < 6 → TrueNo—Demasiado corta
"pythonfp"8 < 6 → FalseSíTrue (no hay dígitos)Necesita un número
"fp1python"9 < 6 → FalseSí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:

Niveles de cliente según el gasto anualCuatro tramos: Básico hasta 500 euros, Silver desde 500, Gold desde 2000 y Platinum desde 5000. Pablo con 499.99 queda en Básico, con 500 en Silver, y Laura con 2500 en Gold más el 5 por ciento de socia.Básico5 %0 €Silver10 %500 €Gold15 %2000 €Platinum20 %5000 €gasto_anual (cada tramo dibujado del mismo ancho)Pablo 499.99Pablo 500.00Laura 2500.00+5 % socio → 20 %
Cada umbral pertenece al tramo de la derecha (>=): 500 € ya es Silver, 499.99 € todavía es Básico.

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.

PasoExpresiónValor
1respuesta_socio"S"
2respuesta_socio.lower()"s"
3"s" == "s"True
4es_socioTrue

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 if con or).

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ácticasCuentanecesariaRamaMensaje
5.5(5 − 2.2) / 0.64.67elseNecesitas al menos un 4.67
9.5(5 − 3.8) / 0.6≈ 2 (1.9999999999999996)elif necesaria <= 4Con el 4 mínimo ya apruebas
0(5 − 0) / 0.68.33elseNecesitas 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:

Las tres ramas de la opción 3Una recta de 0 a 12 dividida en tres zonas: hasta 4, de 4 a 10 y más de 10. Con prácticas 5.5 la nota necesaria es 4.67 y cae en la zona central.necesaria = (5 − 0.4 × 5.5) / 0.6 = 4.67elif necesaria <= 4<= 4: con el 4 mínimo bastaelsede 4 a 10: necesitas esa notaif necesaria > 10> 10: imposible0123456789101112134.67
Con un 5.5 en prácticas hace falta un 4.67: cae en la zona del else y el programa imprime esa nota.

¿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 el else.
  • En la opción 3, comprueba antes de calcular que nota_practicas está 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 elif para comprobaciones independientes. El validador solo informa del primer fallo. Independientes → varios if.
  • 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.
  • and donde iba or (y al revés). «El email está mal si falta la @ o falta el punto» lleva or; con and casi 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 descuento y 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:

  1. En la primera comparación (gasto_anual >= 5000), la flecha no entra en el bloque de Platinum: salta directamente al elif siguiente.
  2. En elif gasto_anual >= 2000, la flecha sí entra: aparecen en el panel nivel = "Gold" y descuento = 15. Después salta por encima de Silver y del else sin tocarlos.
  3. En if es_socio:, mira cómo descuento pasa de 15 a 20 en el panel: la misma variable cambia de valor, no se crea otra.
  4. Al calcular pagaria, comprueba la cuenta en el panel: 2500 − 2500 × 20 / 100 = 2000.0. Cambia es_socio a False y vuelve a ejecutar: verás que el bloque del socio se salta y el resultado pasa a 2125.0.

Resumen

  • Una cadena if/elif/else elige un solo camino; varios if seguidos revisan varias cosas. El validador de registro necesita lo segundo.
  • Con >=, los umbrales van de mayor a menor; al llegar a un elif, todo lo de arriba ya es False y 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 →

Sigue aprendiendo

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *