Saltar al contenido
🐍 Curso de Python
/

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.

⏱ 11 min de lectura

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:

python
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.")
Salida en pantalla
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:

python
if edad >= 21 and tiene_carnet and anos_carnet >= 2:
        print("Puedes alquilar el coche.")
else:
        print("No cumples los requisitos.")
Salida en pantalla
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.

python
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.")
Salida en pantalla
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:

python
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.")
Salida en pantalla
7 es impar

La 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#

python
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#

python
numero = 5

if numero > 0:
        es_positivo = True
else:
        es_positivo = False

print(es_positivo)
Salida en pantalla
True

Cuatro líneas para algo que ya sabes hacer en una: recuerda que una comparación es una expresión que produce un booleano.

python
es_positivo = numero > 0
print(es_positivo)
Salida en pantalla
True

Siempre 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#

python
if edad >= 18:
        precio = 12.00
if edad < 18:            # el segundo if es innecesario
        precio = 6.00

Si 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:

python
numero = 7
mensaje = "par" if numero % 2 == 0 else "impar"
print(mensaje)
Salida en pantalla
impar

Se 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/elseEn una línea
Cuatro líneas, un bloque para cada casoUna línea, una expresión
Puede hacer varias cosas en cada ramaSolo elige entre dos valores

Donde más brilla es dentro de una f-string, para cuadrar los plurales:

python
unidades = 1
print(f"Tienes {unidades} {'unidad' if unidades == 1 else 'unidades'}")

unidades = 4
print(f"Tienes {unidades} {'unidad' if unidades == 1 else 'unidades'}")
Salida en pantalla
Tienes 1 unidad
Tienes 4 unidades

Fíjate en que dentro de la f-string las comillas interiores son simples, porque las dobles ya están ocupadas por la cadena exterior.

python
importe = 120.0
descuento = 0.10 if importe > 100 else 0.0

print(f"Descuento: {descuento:.0%}")
print(f"Total: {importe * (1 - descuento):.2f} €")
Salida en pantalla
Descuento: 10%
Total: 108.00 €