Módulo 1 · Lección 13 de 59
Condiciones anidadas
Poner un if dentro de otro, cuándo conviene aplanarlo, las cláusulas de guarda y los antipatrones que hay que desaprender.
Dentro del bloque de un if puede haber cualquier instrucción, y un if es una instrucción. Así que puedes meter condiciones dentro de condiciones tantos niveles como quieras. El lenguaje te deja; la legibilidad, no tanto.
Esta lección es menos sobre sintaxis nueva y más sobre escribir condiciones que se entiendan. Es la diferencia entre código que funciona y código con el que se puede trabajar.
Un if dentro de otro#
Cada nivel añade cuatro espacios más de sangría:
edad = 25
tiene_carnet = True
anos_carnet = 3
if edad >= 21:
if tiene_carnet:
if anos_carnet >= 2:
print("Puedes alquilar el coche.")
else:
print("Necesitas dos años de carnet.")
else:
print("Necesitas carnet de conducir.")
else:
print("Necesitas tener 21 años.")Puedes alquilar el coche.Funciona, y tiene una virtud: cada else explica exactamente qué requisito ha fallado. Pero fíjate en el precio. La línea que importa está a tres niveles de profundidad, y los else están tan lejos de su if que hay que contar espacios con el dedo para saber cuál va con cuál.
Aplanar con and#
Si lo único que necesitas es saber si se cumple todo, combina las condiciones y quédate en un nivel:
if edad >= 21 and tiene_carnet and anos_carnet >= 2:
print("Puedes alquilar el coche.")
else:
print("No cumples los requisitos.")Puedes alquilar el coche.Tres líneas en lugar de diez y ni una sangría de más. Lo que se pierde es el detalle de qué requisito falló. Esa es la decisión de diseño: si no necesitas distinguir los motivos del fallo, usa and.
Cláusulas de guarda#
Cuando sí necesitas distinguir los motivos, la mejor forma no es anidar, sino darle la vuelta: comprueba primero lo que está mal, resuélvelo y quítalo de en medio.
edad = 19
tiene_carnet = True
anos_carnet = 3
if edad < 21:
print("Necesitas tener 21 años.")
elif not tiene_carnet:
print("Necesitas carnet de conducir.")
elif anos_carnet < 2:
print("Necesitas dos años de carnet.")
else:
print("Puedes alquilar el coche.")Necesitas tener 21 años.Esto hace lo mismo que la versión anidada de tres niveles, pero está todo a un solo nivel de sangría y se lee de arriba abajo como una lista de requisitos. Cada rama que comprueba un problema y lo despacha se llama cláusula de guarda.
En el módulo de funciones verás la forma más potente de este patrón: en lugar de elif, cada guarda termina el trabajo con un return y no hace falta ni la cadena.
Cuándo sí está justificado anidar#
Anidar es correcto cuando la segunda condición solo tiene sentido si la primera se cumple. El caso típico es comprobar que un dato es válido antes de usarlo:
entrada = "7"
if entrada.isdigit():
numero = int(entrada)
if numero % 2 == 0:
print(f"{numero} es par")
else:
print(f"{numero} es impar")
else:
print("No es un número entero.")7 es imparLa comprobación de par o impar necesita que numero exista, y numero solo existe dentro del primer bloque. Aquí el anidamiento refleja la dependencia real entre las dos preguntas, y no se puede aplanar con and porque las dos ramas interiores hacen cosas distintas.
Antipatrones que hay que desaprender#
Son tres formas de escribir condiciones que funcionan perfectamente y que, aun así, delatan a quien lleva poco tiempo con el lenguaje.
Comparar un booleano con True#
activo = True
if activo == True: # redundante
print("Activo")
if activo: # así se escribe
print("Activo")activo ya es True o False. Compararlo con True es como preguntar "¿es verdad que es verdad?". Para el caso contrario, if not activo: en vez de if activo == False:.
Asignar True o False con un if#
numero = 5
if numero > 0:
es_positivo = True
else:
es_positivo = False
print(es_positivo)TrueCuatro líneas para algo que ya sabes hacer en una: recuerda que una comparación es una expresión que produce un booleano.
es_positivo = numero > 0
print(es_positivo)TrueSiempre que veas un if/else en el que las dos ramas asignan True y False a la misma variable, bórralo y asigna directamente la condición.
Repetir la condición en las dos ramas#
if edad >= 18:
precio = 12.00
if edad < 18: # el segundo if es innecesario
precio = 6.00Si el segundo if es exactamente lo contrario del primero, es un else. Además de más corto, el else no puede desincronizarse el día que cambies el umbral de 18 a 21 y te olvides de cambiarlo en los dos sitios.
El operador condicional en una línea#
Para el caso concreto de elegir entre dos valores, Python tiene una forma de expresarlo en una sola línea:
numero = 7
mensaje = "par" if numero % 2 == 0 else "impar"
print(mensaje)imparSe lee de un tirón, aunque el orden sorprenda al principio: valor si se cumple, if, condición, else, valor si no. El valor va delante de la condición, al contrario que en un if normal.
| Con if/else | En una línea |
|---|---|
| Cuatro líneas, un bloque para cada caso | Una línea, una expresión |
| Puede hacer varias cosas en cada rama | Solo elige entre dos valores |
Donde más brilla es dentro de una f-string, para cuadrar los plurales:
unidades = 1
print(f"Tienes {unidades} {'unidad' if unidades == 1 else 'unidades'}")
unidades = 4
print(f"Tienes {unidades} {'unidad' if unidades == 1 else 'unidades'}")Tienes 1 unidad
Tienes 4 unidadesFíjate en que dentro de la f-string las comillas interiores son simples, porque las dobles ya están ocupadas por la cadena exterior.
importe = 120.0
descuento = 0.10 if importe > 100 else 0.0
print(f"Descuento: {descuento:.0%}")
print(f"Total: {importe * (1 - descuento):.2f} €")Descuento: 10%
Total: 108.00 €