📘 2.2 Estructuras Condicionales
Aprende a controlar el flujo de tus programas en Python con decisiones inteligentes y código limpio.
- Parte 1 — Introducción a las estructuras condicionales e instrucciones
if
,elif
,else
- Parte 2 — Condiciones anidadas
- Parte 3 — Operador ternario en Python
- Parte 4 — Estructura
switch
ymatch-case
en Python - Parte 5 — Buenas prácticas y legibilidad del código condicional
- Parte 6 — Ejercicios prácticos y resumen final
🧭 Parte 1 — Introducción a las estructuras condicionales e instrucciones if
, elif
, else
Las estructuras condicionales permiten que tu programa tome decisiones: si ocurre A, haz X; si no, haz Y. En Python, la toma de decisiones se implementa con if
, elif
y else
, apoyadas por comparaciones y operadores lógicos.
✅ Sintaxis básica
La regla de oro de Python es la indentación (sangría): define los bloques de código. Por convención, usa 4 espacios.
edad = 20
if edad >= 18:
print("Eres mayor de edad")
elif edad > 0:
print("Eres menor de edad")
else:
print("Edad no válida")
if
: evalúa una condición. Si esTrue
, ejecuta su bloque.elif
: condiciones adicionales si las anteriores fueronFalse
.else
: caso por defecto cuando todo lo anterior fueFalse
.
tiene_licencia
, saldo_disponible
) para mejorar legibilidad.🧪 Operadores de comparación (devuelven True
o False
)
Operador | Significado | Ejemplo | Resultado |
---|---|---|---|
== | Igual a | 5 == 5 | True |
!= | Distinto de | 5 != 3 | True |
> , < | Mayor / Menor | 7 < 2 | False |
>= , <= | Mayor/menor o igual | 8 >= 8 | True |
in | Contiene | "Py" in "Python" | True |
is | Identidad (mismo objeto) | x is None | Convención c/ None |
usuario = "javier"
if "jav" in usuario and len(usuario) >= 5:
print("Usuario válido")
🔗 Operadores lógicos: and
, or
, not
Sirven para combinar condiciones.
edad = 19
tiene_licencia = True
if edad >= 18 and tiene_licencia:
print("Puedes conducir")
elif edad >= 18 and not tiene_licencia:
print("Necesitas licencia")
else:
print("Aún no puedes")
Operador | Regla | Ejemplo | Evalúa |
---|---|---|---|
and | True si ambos son True | True and False | False |
or | True si alguno es True | False or True | True |
not | Invierte el valor | not True | False |
⚡ Cortocircuito (short-circuit)
Python deja de evaluar cuando ya conoce el resultado. Esto evita errores y mejora rendimiento.
x = 0
# 'and' se corta si la izquierda es False ⇒ no divide por cero
seguro = (x != 0) and (10 / x > 2)
token = "ABC123"
# 'or' se corta si la izquierda es True ⇒ no llama a función costosa
ok = (token is not None) or validar_token_costoso(token)
🧠 Truthiness (valores “verdaderos” y “falsos”)
En un if
, Python considera falsos: False
, None
, 0
, 0.0
, ""
, []
, ()
, {}
, set()
. Todo lo demás es verdadero.
nombre = ""
if nombre:
print("Hola", nombre)
else:
print("Nombre no proporcionado")
🧩 Patrones comunes con if
, elif
, else
1) Validación de entrada
texto = input("Edad: ")
if texto.isdigit():
edad = int(texto)
if edad >= 18:
print("Mayor de edad")
else:
print("Menor de edad")
else:
print("Entrada no válida")
2) Rango con comparaciones encadenadas
nota = 7.5
if 0 <= nota <= 10:
print("Nota válida")
else:
print("Nota fuera de rango")
3) Múltiples ramas bien estructuradas
rol = "editor"
if rol == "admin":
acceso = "total"
elif rol == "editor":
acceso = "parcial"
elif rol == "invitado":
acceso = "limitado"
else:
acceso = "denegado"
print("Acceso:", acceso)
🛡️ Errores típicos y cómo evitarlos
- Olvidar el casting al leer
input()
(que siempre esstr
). - Usar
== None
en lugar deis None
para comprobar ausencia de valor. - Comparar tipos incompatibles (p. ej.,
"10" > 5
lanzaTypeError
). - Indentación inconsistente (mezclar espacios y tabuladores). Configura tu editor a 4 espacios.
# ✅ None seguro
resultado = obtener_dato()
if resultado is None:
print("Sin datos")
📏 Estilo y legibilidad desde el día 1
- Prefiere condiciones positivas y simples:
if activo:
mejor queif not desactivado:
- Evita “piramidar”
if
: extrae funciones o usa retornos tempranos. - Usa variables booleanas intermedias para documentar la intención:
es_mayor_de_edad = edad >= 18
if es_mayor_de_edad:
habilitar_compra()
🧪 Mini-ejercicios
- Pide un número y muestra si es positivo, negativo o cero.
- Solicita usuario y contraseña: si ambos no están vacíos, imprime “Acceso concedido”, si no, “Acceso denegado”.
- Lee una nota (0–10) y muestra: “Matrícula (≥9)”, “Aprobado (≥5)”, “Suspenso (<5)”, o “Inválida”.
🏁 Conclusión
Ya dominas la base de las decisiones con if
, elif
y else
. En la Parte 2 profundizaremos en condiciones anidadas y cómo simplificarlas sin perder legibilidad.
🧱 Parte 2 — Condiciones anidadas
Las condiciones anidadas aparecen cuando colocas uno o más if
dentro de otro if
. Son útiles, pero abusar de ellas crea la famosa pirámide del terror: código difícil de leer, probar y mantener. En esta parte aprenderás a anidar bien… y a evitar anidar cuando conviene.
🔎 Ejemplo básico de anidación
usuario = {"activo": True, "rol": "editor", "edad": 21}
if usuario:
if usuario["activo"]:
if usuario["edad"] >= 18:
if usuario["rol"] in ("admin", "editor"):
print("Acceso concedido")
else:
print("Rol insuficiente")
else:
print("Menor de edad")
else:
print("Usuario inactivo")
else:
print("Usuario inexistente")
Funciona… pero es poco legible. Veamos técnicas para simplificar.
🛡️ Patrón 1 — Guard Clauses (retornos tempranos)
Consiste en salir antes cuando falla un requisito. Dejas el camino feliz más plano.
def puede_acceder(usuario):
if not usuario:
return "Usuario inexistente"
if not usuario.get("activo"):
return "Usuario inactivo"
if usuario.get("edad", 0) < 18:
return "Menor de edad"
if usuario.get("rol") not in ("admin", "editor"):
return "Rol insuficiente"
return "Acceso concedido"
print(puede_acceder({"activo": True, "rol": "editor", "edad": 21}))
- Ventaja: menos indentación, intención más clara.
- Tip: ordena las comprobaciones de la más barata a la más cara.
🧰 Patrón 2 — Combinación de condiciones
Si dependes de varias condiciones booleanas, combínalas con and
/or
o usa variables intermedias con nombres claros.
edad_ok = usuario and usuario.get("edad", 0) >= 18
rol_ok = usuario and usuario.get("rol") in ("admin", "editor")
activo_ok = usuario and usuario.get("activo") is True
if usuario and activo_ok and edad_ok and rol_ok:
print("Acceso concedido")
else:
print("Acceso denegado")
Mejor aún con explicadores (variables booleanas con intención).
🧠 Patrón 3 — De Morgan para simplificar negaciones
Evita acumular not
anidados reescribiendo la lógica:
Antes (difícil) | Después (claro) |
---|---|
if not (a and b): | if not a or not b: |
if not (x or y): | if not x and not y: |
# Evita doble negación:
if not (activo_ok and edad_ok):
print("Falta requisito")
🧩 Patrón 4 — Salidas tempranas con excepciones (en validaciones estrictas)
En funciones de validación, es más claro fallar rápido lanzando excepciones.
def validar_pedido(pedido):
if not pedido:
raise ValueError("Pedido vacío")
if pedido["importe"] <= 0:
raise ValueError("Importe inválido")
if pedido["estado"] not in {"nuevo", "pagado"}:
raise ValueError("Estado no permitido")
return True
Queda código lineal y sin nidos. Maneja las excepciones donde corresponda.
🧮 Patrón 5 — Diccionarios como “switch” (mapa de decisiones)
Para decisiones por valor (antes de match
), usa un diccionario de funciones o resultados.
def crear(): return "Creando…"
def leer(): return "Leyendo…"
def borrar(): return "Borrando…"
acciones = {
"CREATE": crear,
"READ": leer,
"DELETE": borrar,
}
oper = "READ"
resultado = acciones.get(oper, lambda: "Operación no soportada")()
print(resultado)
Menos elif
, más claridad y extensibilidad.
📏 Patrón 6 — Validaciones encadenadas (pipeline)
Encapsula reglas en funciones pequeñas y compón un pipeline.
def regla_edad(u): return (u.get("edad", 0) >= 18, "Menor de edad")
def regla_activo(u): return (u.get("activo") is True, "Usuario inactivo")
def regla_rol(u): return (u.get("rol") in {"admin","editor"}, "Rol insuficiente")
def validar(u):
for check, msg in (regla_edad, regla_activo, regla_rol):
ok, error = check(u)
if not ok:
return error
return "Acceso concedido"
print(validar({"edad": 21, "activo": True, "rol": "editor"}))
🧪 Antes y después — Refactor real
❌ Versión anidada
def precio_final(p, cupon):
if p > 0:
if cupon is not None:
if cupon == "DESC10":
return p * 0.9
else:
return p
else:
return p
else:
return 0
✅ Versión plana (guard clauses + early return)
def precio_final(p, cupon):
if p <= 0:
return 0
if cupon == "DESC10":
return p * 0.9
return p
Menos ramas, misma lógica, mayor legibilidad.
⚡ Cortocircuito para proteger operaciones
# Evita división por cero
den = 0
seguro = (den != 0) and (100 / den > 1) # No evalúa la derecha si den == 0
Úsalo siempre que una comprobación pueda evitar errores (E/S, llamadas costosas, etc.).
🧼 Checklist anti-pirámide
- ¿Puedo salir antes con un retorno/continue/break?
- ¿Puedo combinar condiciones o extraer booleanos con nombre?
- ¿Este elif es en realidad un diccionario de decisiones?
- ¿Puedo mover validaciones a funciones pequeñas (pipeline)?
- ¿Hay dobles negaciones que simplificar con De Morgan?
🧠 Mini-ejercicios
- Guard clauses: refactoriza una función de login con 4 niveles de
if
para que tenga retornos tempranos (usuario, activo, password, MFA). - Switch dict: implementa un router de comandos (
ADD
,LIST
,DELETE
) sin usar múltipleselif
. - Pipeline: escribe tres reglas de validación sobre un formulario y compón un validador que devuelva el primer error.
🏁 Conclusión
Has aprendido a controlar la complejidad de las condiciones anidadas con patrones profesionales: guard clauses, diccionarios como switch, pipelines y reglas de estilo. En la Ahora veremos el operador ternario para expresiones concisas y seguras.
⚡ Parte 3 — Operador ternario en Python
El llamado operador ternario en Python se expresa como una expresión condicional con la forma:valor_si_verdadero if condicion else valor_si_falso
. Su objetivo es escribir condiciones simples en una sola línea sin perder legibilidad.
✅ Sintaxis básica
edad = 19
mensaje = "Mayor de edad" if edad >= 18 else "Menor de edad"
print(mensaje)
- Se usa cuando hay dos ramas simples y ambas devuelven un valor.
- Es una expresión: puede aparecer en asignaciones, f-strings, retornos, comprensiones, etc.
🧩 Comparación con if/else
de bloque
Bloque tradicional | Ternario | Cuándo usar |
---|---|---|
|
| Cuando la lógica es corta y devuelve un valor directo. |
🎯 Usos frecuentes
1) Asignación condicional
descuento = 0.10 if cliente_vip else 0.00
2) En return
dentro de funciones
def etiqueta_edad(edad):
return "18+" if edad >= 18 else "U18"
3) En f-strings
stock = 3
print(f"Estado: {'OK' if stock > 0 else 'SIN STOCK'}")
4) En comprensiones
nums = [1, 2, 3, 4, 5]
paridad = ["par" if n % 2 == 0 else "impar" for n in nums]
print(paridad) # ['impar', 'par', 'impar', 'par', 'impar']
🧠 Ternario vs. patrones con and
/or
En Python existe el idiom cond and a or b
, pero no es equivalente en todos los casos por la truthiness (si a
es falsy, se devolverá b
aunque la condición sea verdadera). Prefiere SIEMPRE el ternario estándar.
# ❌ Evita:
resultado = condicion and valor_si_verdadero or valor_si_falso
# ✅ Correcto:
resultado = valor_si_verdadero if condicion else valor_si_falso
🧼 Buenas prácticas de legibilidad
- Úsalo para decisiones simples (una sola condición, dos resultados claros).
- Evita anidar ternarios si pierdes claridad. Prefiere
if/elif/else
de bloque omatch
(Parte 4). - Coloca la condición en el centro y mantén valores cortos a izquierda/derecha.
- No metas efectos secundarios (llamadas complejas) dentro del ternario; evalúa antes en variables.
# 👎 Difícil de leer:
msg = "OK" if x > 0 else ("CERO" if x == 0 else "NEGATIVO")
# 👍 Mejor:
if x > 0:
msg = "OK"
elif x == 0:
msg = "CERO"
else:
msg = "NEGATIVO"
🛡️ Patrones seguros
1) Evitar llamadas costosas duplicadas
precio = obtener_precio()
precio_final = (precio * 0.9) if es_vip else precio
2) Normalizar valores con None
nombre = None
visible = nombre if nombre is not None else "Anónimo"
3) Mensajes / etiquetas cortas
valido = len(password) >= 8
estado = "✔️ Fuerte" if valido else "⚠️ Débil"
4) Casting condicionado
dato = "3.14"
num = float(dato) if dato.replace('.', '', 1).isdigit() else None
🔍 Anti-patrones y errores comunes
- Demasiadas condiciones en un ternario → usa
if/elif/else
omatch
. - Usar el idiom
cond and A or B
→ puede fallar siA
es falsy. - Romper líneas sin paréntesis → usa paréntesis para mejorar lectura.
# 👎 Ternario largo sin paréntesis
resultado = "A" if a and b or (c and not d) else "B"
# 👍 Más claro
resultado = (
"A"
if (a and b) or (c and not d)
else "B"
)
🧪 Mini-ejercicios
- Crear una variable
riesgo
que sea"ALTO"
sitemp >= 38.0
y"OK"
en caso contrario. - Con un valor
saldo
, definirestado
como"en descubierto"
sisaldo < 0
y"positivo"
si no. - Dada una cadena
correo
, asignarvalido
aTrue
si contiene"@"
y"."
(ambas), si noFalse
(puedes usar un ternario o una expresión booleana directa). - Generar una lista
signos
desdenums
con"+"
si el número es >= 0 y"-"
si es < 0 (usa comprensión con ternario).
🏁 Conclusión
El ternario de Python es ideal para decisiones concisas que devuelven un valor. Úsalo con mesura y premia la claridad. En la Ahora veremos cómo cubrir casos múltiples con switch/match, la alternativa moderna y legible para varias ramas.
🔀 Parte 4 — Estructura switch
y match-case
en Python
Python no tuvo switch
tradicional como C/Java. Históricamente se resolvía con diccionarios de despacho (dispatch dict) o cadenas de if/elif
. Desde Python 3.10, disponemos de match
(coincidencia estructural) para casos múltiples, potente y legible.
match
requiere Python ≥ 3.10. Si apuntas a versiones anteriores, usa el patrón de diccionario de funciones.🧰 Patrón “switch” con diccionario de despacho
Mapa de clave → acción. Evita múltiples elif
, es más limpio y escalable.
def crear(): return "Creando…"
def leer(): return "Leyendo…"
def borrar(): return "Borrando…"
DISPATCH = {
"CREATE": crear,
"READ": leer,
"DELETE": borrar,
}
oper = "READ"
resultado = DISPATCH.get(oper, lambda: "Operación no soportada")()
print(resultado) # "Leyendo…"
- Ventajas: extensible, testable, muy claro para comandos.
- Fallback: provee una función por defecto via
.get(..., lambda: ...)
.
🧠 Variantes del dispatch
1) Con argumentos
def cuadrado(x): return x*x
def doble(x): return 2*x
ops = {"sq": cuadrado, "dbl": doble}
cmd, valor = "dbl", 7
print(ops.get(cmd, lambda v: v)(valor)) # 14
2) Con valores de retorno simples
mensajes = {
200: "OK",
404: "No encontrado",
500: "Error interno",
}
codigo = 404
print(mensajes.get(codigo, "Desconocido"))
3) Con clases/estrategias
class Crear: def __call__(self): return "Creando…"
class Leer: def __call__(self): return "Leyendo…"
class Borrar: def __call__(self): return "Borrando…"
acciones = {"CREATE": Crear(), "READ": Leer(), "DELETE": Borrar()}
print(acciones.get("DELETE", lambda: "No soportado")())
🧩 match-case
: coincidencia estructural (Python ≥ 3.10)
match
permite describir formas de los datos (patrones). Es más que un switch: entiende literales, tuplas, secuencias, dict
, clases, uniones, y añade guardas (if
en el case).
✅ Literales y default (_
)
def estado_http(codigo):
match codigo:
case 200:
return "OK"
case 404:
return "No encontrado"
case 500:
return "Error interno"
case _:
return "Desconocido"
print(estado_http(404))
🎯 Varios literales en un mismo caso (OR)
def es_vocal(c):
match c.lower():
case "a" | "e" | "i" | "o" | "u":
return True
case _:
return False
📦 Patrones de secuencia (listas/tuplas)
def forma(secuencia):
match secuencia:
case [x, y]: # lista de 2 elementos
return f"Par: ({x}, {y})"
case [x, y, z]: # lista de 3
return f"Triple: {x},{y},{z}"
case [primero, *_]: # lista con al menos 1 (resto ignorado)
return f"Empieza por {primero}"
case _:
return "No coincide"
print(forma([10, 20, 30]))
🗺️ Patrones de diccionario
def describe(evento):
match evento:
case {"type": "login", "user": usuario}:
return f"Login de {usuario}"
case {"type": "error", "code": c} if c >= 500: # guarda
return f"Error grave {c}"
case {"type": "error", "code": c}:
return f"Error {c}"
case _:
return "Evento desconocido"
print(describe({"type": "error", "code": 503}))
🏷️ Patrones de clase (con atributos)
from dataclasses import dataclass
@dataclass
class Pedido:
id: int
importe: float
vip: bool = False
def procesa(p):
match p:
case Pedido(id=pid, importe=imp, vip=True) if imp >= 100:
return f"Pedido VIP {pid} con descuento"
case Pedido(id=pid, importe=imp):
return f"Pedido {pid} por {imp:.2f}"
case _:
return "Objeto no compatible"
print(procesa(Pedido(101, 120, True)))
🧪 Patrones con alias (as
)
def analizar(x):
match x:
case {"ok": True, **resto} as completo:
# alias 'completo' captura el dict entero
return ("válido", completo)
case _:
return ("inválido", x)
print(analizar({"ok": True, "data": [1,2,3]}))
🛡️ Guardas (condiciones en el case
)
Permiten refinar el patrón con una condición booleana.
def clasificar(n):
match n:
case int() if n < 0:
return "negativo"
case int() if n == 0:
return "cero"
case int():
return "positivo"
case float():
return "decimal"
case _:
return "no numérico"
⚠️ Errores comunes y cómo evitarlos
- Olvidar el default: usa
case _:
para cubrir casos no contemplados. - Patrones demasiado específicos: si el dato cambia levemente, no coincidirá. Añade guardas o casos más amplios.
- Versión de Python: si distribuyes a entornos < 3.10, provee fallback (dispatch dict).
- Lógica pesada en casos: mueve el trabajo a funciones; los
case
deben ser declarativos.
🧼 Buenas prácticas
- Para comandos/acciones sencillas → usa dispatch dict.
- Para estructuras de datos (secuencias, dicts, objetos) → usa
match
. - Usa guardas para reglas de negocio sin sobre-crear patrones.
- Mantén cada
case
corto; delega a funciones y retorna temprano.
🧪 Mini-ejercicios
- Implementa un router con dispatch dict para
POST
,GET
,PUT
,DELETE
; añade fallback. - Usa
match
para identificar tokens de una calculadora:('+', a, b)
,('num', x)
,('err', msg)
. - Con
match
, procesa eventos de pago:{"type":"paid","amount":>=100}
aplica descuento VIP (usa guarda), otros muestran total normal.
🏁 Conclusión
Python ofrece dos vías para “switch”: el dispatch dict (simple, retrocompatible) y match-case
(poderoso y expresivo). Elige según tu audiencia (versión de Python) y la complejidad de los datos.
🧼 Parte 5 — Buenas prácticas de legibilidad en estructuras condicionales
En Python, escribir código que funcione es solo el primer paso; lo que diferencia a un buen desarrollador es su capacidad de escribir código que se entienda, se mantenga y se escale.
Las estructuras condicionales (if
, elif
, else
, match
) son uno de los puntos donde más se nota la calidad del estilo.
Aquí aprenderás a aplicar la filosofía del “Zen de Python” a tus decisiones lógicas.
📜 Recordemos algunos principios del Zen de Python
Beautiful is better than ugly.
Simple is better than complex.
Readability counts.
There should be one—and preferably only one—obvious way to do it.
Estas líneas se aplican directamente a cómo escribes tus condiciones. Menos anidaciones, nombres claros y estructura coherente.
✅ 1. Mantén las condiciones simples y legibles
Evita expresiones complejas con varios operadores lógicos encadenados. Divide en pasos o usa variables auxiliares descriptivas.
# 👎 Difícil de leer
if (edad >= 18 and permiso and not suspendido and (pais == "ES" or pais == "PT")):
print("Puede conducir")
# 👍 Mejor legibilidad
mayor_edad = edad >= 18
pais_valido = pais in ("ES", "PT")
if mayor_edad and permiso and not suspendido and pais_valido:
print("Puede conducir")
🧱 2. Usa guard clauses para evitar pirámides
En lugar de anidar condicionales, sal temprano del flujo cuando una comprobación falla. Esto aplanará tu estructura.
def procesar(usuario):
if not usuario:
return "Error: usuario inexistente"
if not usuario.get("activo"):
return "Error: usuario inactivo"
if usuario.get("edad", 0) < 18:
return "Error: menor de edad"
return "Usuario válido"
Ventaja: mejora la lectura y reduce el número de tabulaciones.
🔍 3. Evalúa expresiones en el orden más lógico
Ordena las comprobaciones de la más rápida y segura a la más compleja o costosa.
Aprovecha el cortocircuito (and
/or
) para evitar errores y optimizar rendimiento.
# 👎 Mal orden
if usuario["activo"] and usuario and usuario["edad"] > 18:
...
# 👍 Correcto
if usuario and usuario.get("activo") and usuario.get("edad", 0) > 18:
...
🧠 4. Prefiere condiciones positivas
Las condiciones positivas son más naturales de leer que las negativas.
En vez de “si no está inactivo”, escribe “si está activo”.
# 👎 Negativo doble
if not no_valido:
procesar()
# 👍 Positivo directo
if valido:
procesar()
🧩 5. Evita redundancias en if
# 👎 Redundante
if es_valido == True:
ejecutar()
# 👍 Correcto
if es_valido:
ejecutar()
Del mismo modo, no compares booleanos con == False
; usa not variable
.
⚙️ 6. Agrupa condiciones similares
Si varias condiciones producen el mismo resultado, agrúpalas con in
o tuplas.
# 👎
if pais == "ES" or pais == "PT" or pais == "FR":
print("País admitido")
# 👍
if pais in ("ES", "PT", "FR"):
print("País admitido")
🧮 7. Usa funciones pequeñas para separar decisiones
Una función que tenga muchos if
puede dividirse en funciones auxiliares con un nombre descriptivo.
Esto mejora el entendimiento y favorece el testeo.
def es_mayor(edad): return edad >= 18
def tiene_permiso(u): return u.get("permiso", False)
def puede_conducir(u):
return es_mayor(u.get("edad", 0)) and tiene_permiso(u)
🧾 8. Sigue las recomendaciones PEP 8
Regla | Ejemplo correcto | Incorrecto |
---|---|---|
Espacios antes y después de operadores | if x == 10: | if x==10: |
Indentación de 4 espacios |
|
|
Sin paréntesis innecesarios | if activo: | if (activo): |
Usar is /is not con None | if valor is None: | if valor == None: |
💬 9. Escribe comentarios útiles, no obvios
# 👎 Innecesario
if x > 0: # Si x es mayor que cero
...
# 👍 Explica la intención, no el código
if x > 0: # Evitamos divisiones por cero en la siguiente operación
...
📦 10. Usa match
cuando tengas muchos casos
En lugar de cadenas de elif
, match
mejora la lectura y te fuerza a cubrir todos los casos.
Es ideal cuando tienes niveles, tipos, estados o comandos.
def clasificar(puntaje):
match puntaje:
case p if p >= 90: return "Excelente"
case p if p >= 70: return "Aprobado"
case p if p >= 50: return "Regular"
case _: return "Insuficiente"
El orden lógico de evaluación mejora la comprensión y reduce errores.
🧪 Ejemplo completo — Antes y después
❌ Código sin estilo
def procesar(p):
if p:
if p["monto"] > 0:
if p["estado"] == "pagado":
print("Pedido confirmado")
else:
print("Estado no válido")
else:
print("Monto incorrecto")
else:
print("Sin datos")
✅ Código limpio
def procesar(p):
if not p:
return "Sin datos"
if p["monto"] <= 0:
return "Monto incorrecto"
if p["estado"] != "pagado":
return "Estado no válido"
return "Pedido confirmado"
Resultado: menos indentación, más claridad, control de flujo evidente.
🧠 Mini-ejercicios
- Refactoriza una función con 4 niveles de
if
usando guard clauses. - Usa variables intermedias descriptivas para reemplazar una condición de más de 3 operadores.
- Convierte una serie de
elif
en unmatch
con casos claros y un_
por defecto. - Revisa un código tuyo e identifica comparaciones redundantes (por ejemplo,
if var == True
).
🏁 Conclusión
La legibilidad es la piedra angular del código profesional. En Python, las estructuras condicionales deben reflejar la intención, no solo la lógica.
Recuerda: menos anidaciones, más claridad; nombres expresivos, menos comentarios obvios.
En la Parte 6 aplicaremos todo lo aprendido con ejercicios integradores que combinan if
, elif
, else
, match
y las buenas prácticas vistas hasta ahora.
🎯 Parte 6 — Ejercicios prácticos y resumen final
Has llegado al final del módulo de Estructuras Condicionales.
Ahora consolidaremos lo aprendido con ejercicios prácticos que mezclan if
, elif
, else
, el operador ternario y la estructura moderna match-case.
Aquí pondrás en práctica tus habilidades para analizar, decidir y escribir código claro.
🧩 Ejercicio 1 — Clasificador de temperatura
Escribe un programa que pida la temperatura actual y clasifique el clima.
temp = float(input("Temperatura actual (°C): "))
if temp <= 0:
print("❄️ Muy frío")
elif temp <= 15:
print("🌤 Frío")
elif temp <= 25:
print("☀️ Templado")
elif temp <= 35:
print("🔥 Caluroso")
else:
print("🥵 Extremo")
✅ Conceptos: comparaciones encadenadas, elif
múltiple, legibilidad y claridad.
⚙️ Ejercicio 2 — Menú interactivo con match-case
Implementa un pequeño menú de opciones usando match
(Python ≥ 3.10).
print("=== MENÚ PRINCIPAL ===")
print("1. Saludar")
print("2. Mostrar hora")
print("3. Salir")
opcion = input("Elige una opción (1-3): ")
match opcion:
case "1":
print("👋 ¡Hola, usuario!")
case "2":
from datetime import datetime
print("🕒 Hora actual:", datetime.now().strftime("%H:%M:%S"))
case "3":
print("👋 Hasta pronto.")
case _:
print("❌ Opción no válida")
✅ Conceptos: match-case
, patrón por literales, _
(default), modularidad.
📦 Ejercicio 3 — Validación de formulario
Usa condiciones y retornos tempranos para validar datos de usuario.
def validar_formulario(nombre, edad, correo):
if not nombre:
return "❌ Error: el nombre es obligatorio."
if not edad.isdigit() or int(edad) <= 0:
return "❌ Error: la edad debe ser un número positivo."
if "@" not in correo or "." not in correo:
return "❌ Error: el correo no es válido."
return "✅ Formulario válido."
# Ejemplo de prueba
print(validar_formulario("Javier", "25", "javi@example.com"))
✅ Conceptos: guard clauses, validación booleana, composición lógica.
🧮 Ejercicio 4 — Calculadora avanzada (ternario + match)
print("=== CALCULADORA ===")
a = float(input("Número 1: "))
b = float(input("Número 2: "))
op = input("Operación (+, -, *, /): ")
match op:
case "+":
print(f"Resultado: {a + b}")
case "-":
print(f"Resultado: {a - b}")
case "*":
print(f"Resultado: {a * b}")
case "/":
print("Resultado:", a / b if b != 0 else "❌ División por cero")
case _:
print("Operación no válida")
✅ Conceptos: match
, ternario, condiciones anidadas simplificadas.
🧠 Ejercicio 5 — Clasificador de edades
Combina el uso del operador ternario dentro de una lista por comprensión.
edades = [3, 12, 17, 25, 65]
categorias = [
"Niño" if e < 13 else "Adolescente" if e < 18 else "Adulto" if e < 60 else "Mayor"
for e in edades
]
print(categorias)
✅ Conceptos: ternario anidado, comprensión de listas, legibilidad.
🧠 Ejercicio 6 — Sistema de acceso (anidación + refactorización)
Versión “antes y después” para aplicar buenas prácticas.
❌ Versión inicial (anidada)
usuario = {"nombre": "Javier", "activo": True, "rol": "admin"}
if usuario:
if usuario["activo"]:
if usuario["rol"] == "admin":
print("✅ Acceso total")
else:
print("⛔ Acceso restringido")
else:
print("🚫 Usuario inactivo")
else:
print("❌ Usuario no encontrado")
✅ Versión refactorizada (guard clauses)
if not usuario:
print("❌ Usuario no encontrado")
elif not usuario["activo"]:
print("🚫 Usuario inactivo")
elif usuario["rol"] != "admin":
print("⛔ Acceso restringido")
else:
print("✅ Acceso total")
✅ Conceptos: simplificación estructural, claridad, control de flujo limpio.
🎨 Ejercicio 7 — Analizador de productos (match con diccionarios)
productos = [
{"nombre": "Manzana", "categoria": "Fruta", "precio": 1.2},
{"nombre": "Leche", "categoria": "Lácteo", "precio": 2.0},
{"nombre": "Pan", "categoria": "Cereal", "precio": 1.0},
]
for p in productos:
match p:
case {"categoria": "Fruta", "precio": precio} if precio < 2:
print(f"🍎 {p['nombre']} en promoción")
case {"categoria": "Lácteo"}:
print(f"🥛 {p['nombre']} requiere refrigeración")
case {"categoria": "Cereal"}:
print(f"🍞 {p['nombre']} de panadería")
case _:
print(f"{p['nombre']} no clasificado")
✅ Conceptos: match-case
, patrones de diccionarios, guardas y estructura clara.
💬 Mini-repaso visual
Estructura | Uso recomendado | Ejemplo |
---|---|---|
if / elif / else | Decisiones simples o jerárquicas | if edad >= 18: ... |
Condiciones anidadas | Evitar; usar guardas o funciones | if a: if b: ... |
Operador ternario | Asignaciones breves | msg = "OK" if ok else "ERR" |
Dispatch dict | “Switch” retrocompatible | acciones.get(cmd, defecto)() |
match-case | Casos múltiples con patrones estructurados | match x: case _: ... |
🧾 Autoevaluación final
Verifica si ya dominas estas competencias:
- ✅ Comprendo cuándo usar
if
,elif
yelse
. - ✅ Sé escribir condiciones limpias y sin redundancias.
- ✅ Puedo usar guard clauses para simplificar estructuras.
- ✅ Sé aplicar el operador ternario con legibilidad.
- ✅ Sé usar match-case para manejar múltiples ramas de decisión.
🏁 Conclusión de la Lección
Las estructuras condicionales son el corazón del control de flujo en Python.
Dominar su sintaxis es solo el comienzo; el verdadero objetivo es escribir código claro, coherente y expresivo.
Recuerda:
- 🧠 Piensa antes de anidar. Cada nivel extra de indentación es una capa más de complejidad.
- 💡 Refactoriza temprano. Convierte condiciones en funciones descriptivas.
- ⚙️ Usa el operador ternario para expresiones simples.
- 🧩 Explora
match-case
para decisiones más expresivas. - 📏 Lee tu código en voz alta: si suena complicado, probablemente lo sea.
➡️ En la próxima lección entraremos en el fascinante mundo de las estructuras de repetición (for
, while
do while
), donde aprenderás a automatizar tareas y recorrer colecciones con elegancia.