Tabla de Contenidos
Condiciones y toma de decisiones
En este módulo verás cómo hacer que el programa elija.
Este módulo forma parte del curso de programación desde cero con Python
Módulo 6. Condiciones y toma de decisiones
Hasta ahora tus programas ejecutan siempre las mismas instrucciones, en el mismo orden, sin importar qué datos reciben. El programa que pide una edad y calcula el año siguiente siempre suma 1, aunque el usuario introduzca un texto o un número negativo. Es hora de que el programa decida: que ejecute unas instrucciones u otras según el valor de los datos. Ese es el propósito de las estructuras condicionales, y es lo que separa un programa rígido de uno que responde a su entorno.
1. Título y alcance
Título: Condiciones y toma de decisiones: hacer que el programa elija.
Alcance: Comprender qué es una condición booleana y cómo se evalúa; usar if, elif y else para ramificar la ejecución; construir condiciones compuestas con and, or y not; entender qué valores son verdaderos y falsos (truthiness); anidar condiciones sin caer en la complejidad innecesaria; usar la expresión condicional x if C else y; introducir match/case para comparaciones múltiples sobre un mismo valor; y reconocer los errores lógicos más comunes en las decisiones. Se presupone el uso de variables, tipos y operadores del Módulo 4, y la entrada/salida del Módulo 5, pero no se introducen bucles (Módulo 7) ni funciones propias (Módulo 9).
2. Objetivos de aprendizaje
Al terminar este módulo serás capaz de:
1. Explicar qué es una condición booleana y cómo Python la evalúa.
2. Escribir estructuras if, if-else e if-elif-else correctamente indentadas.
3. Construir condiciones compuestas con and, or y not, respetando la prioridad y la evaluación de cortocircuito.
4. Identificar qué valores son falsy (evaluados como False) y cuáles truthy (evaluados como True).
5. Anidar condiciones cuando sea necesario, y saber cuándo es mejor evitar el anidamiento.
6. Usar la expresión condicional x if C else y para asignaciones simples.
7. Emplear match/case para comparar un valor contra varios patrones de forma legible.
8. Diagnosticar errores lógicos típicos: condiciones mal formuladas, ramas inalcanzables, uso incorrecto de = frente a ==.
3. Conocimientos previos
- Del Módulo 3: Indentación significativa, sintaxis y errores de sintaxis.
- Del Módulo 4: Variables, tipos (bool, int, float, str, NoneType), operadores de comparación (==, !=, <, >, etc.) y operadores lógicos (and, or, not).
- Del Módulo 5: input(), conversión de tipos y f-strings.
- Ningún conocimiento de estructuras de control de flujo.
4. Introducción motivadora: el programa que siempre hace lo mismo
Piensa en un cajero automático que siempre entrega 50 €, independientemente de si el usuario ha solicitado 20 €, 50 € o 100 €. No es un cajero: es una máquina expendedora de un único producto. Un programa útil debe examinar una situación y actuar en consecuencia. Si la edad es menor de 18, no permite el acceso; si el saldo es suficiente, autoriza la compra; si la contraseña es correcta, abre la sesión.
Cada una de esas acciones requiere una condición (una expresión que se evalúa como verdadera o falsa) y una estructura de decisión (la forma de indicar qué hacer en cada caso). En este módulo aprenderás las tres herramientas que Python ofrece para ello: if/elif/else, la expresión condicional y match/case.
5. Explicación paso a paso
5.1. La condición booleana
Una condición es cualquier expresión que Python puede evaluar en un contexto booleano, es decir, que se reduce a True o False. La forma más obvia es una comparación:
edad = 20 print(edad >= 18) # True
Pero en Python cualquier objeto puede usarse como condición. La regla general, documentada en la referencia de tipos incorporados, es que un objeto se considera verdadero a menos que su clase defina __bool__() devolviendo False o __len__() devolviendo 0. En la práctica, esto significa que los siguientes valores son falsy (se comportan como False en una condición):
- None y False.
- El cero de cualquier tipo numérico: 0, 0.0, 0j, Decimal(0), Fraction(0, 1).
- Las secuencias y colecciones vacías: "", (), [], {}, set(), range(0).
Cualquier otro valor es truthy (se comporta como True). Esto incluye cadenas no vacías, números distintos de cero y objetos creados por el usuario.
[PYTHON] Esta evaluación implícita de cualquier objeto en un contexto booleano es característica de Python y de algunos otros lenguajes dinámicos. En C, por ejemplo, una condición debe ser un entero o un puntero; en Java, debe ser estrictamente unboolean. Python permite escribirif lista:en lugar deif len(lista) > 0, lo que resulta más legible, pero exige comprender qué se está evaluando realmente.
[ERROR HABITUAL] Confundirif x:conif x is not None:. Sixes0,if x:esFalse, peroxno esNone. Cuando quieras comprobar si un valor es distinto deNone, sé explícito:if x is not None:. Cuando quieras comprobar si una colección tiene elementos,if coleccion:es idiomático.
5.2. `if`: la decisión más simple
La estructura if ejecuta un bloque de instrucciones solo si la condición es verdadera:
edad = 20 if edad >= 18: print("Eres mayor de edad")
Reglas sintácticas:
- La línea del if termina en dos puntos (:).
- El bloque que depende del if va indentado con 4 espacios (PEP 8).
- El bloque puede contener una o varias instrucciones.
- Si la condición es falsa, el bloque no se ejecuta y el programa continúa con la siguiente instrucción no indentada.
[ERROR HABITUAL] Olvidar los dos puntos al final de la líneaifproduce unSyntaxError. Olvidar la indentación del bloque produce unIndentationError. Ambos son errores de sintaxis y el programa no se ejecuta en absoluto.
5.3. `else`: la alternativa
else ejecuta un bloque cuando ninguna de las condiciones anteriores se cumplió:
edad = 15 if edad >= 18: print("Eres mayor de edad") else: print("Eres menor de edad")
else no lleva condición propia: se ejecuta si el if (y los elif, si los hay) no se cumplieron. Solo puede haber un else por estructura, y debe ir al final.
5.4. `elif`: múltiples alternativas
elif es la abreviatura de “else if”. Permite comprobar varias condiciones en orden. La primera que se cumpla ejecuta su bloque y las demás se ignoran, aunque también sean verdaderas.
nota = 85 if nota >= 90: print("Sobresaliente") elif nota >= 70: print("Notable") elif nota >= 60: print("Aprobado") else: print("Suspenso")
Seguimiento: nota es 85. La primera condición (>= 90) es falsa. La segunda (>= 70) es verdadera, así que se ejecuta print("Notable") y el resto de la estructura se omite. Aunque 85 también cumple >= 60, esa rama no se evalúa.
[BUENA PRÁCTICA] Ordena las condiciones deelifde la más específica a la más general, o de la más restrictiva a la más permisiva. Si empiezas connota >= 60, la rama denota >= 90nunca se alcanzará. Las ramas inalcanzables son un error lógico silencioso: el programa funciona, pero no hace lo que esperas.
[PYTHON] La secuenciaif … elif … elif …es el sustituto de Python para elswitchocasede otros lenguajes, como señala el tutorial oficial. Sin embargo, para comparaciones sobre un mismo valor,match/case(apartado 5.9) puede ser más claro. Para condiciones que combinan variables distintas,if/elifsigue siendo la opción natural.
5.5. Condiciones compuestas
Puedes combinar condiciones con and, or y not:
- A and B es verdadero solo si ambas son verdaderas.
- A or B es verdadero si al menos una es verdadera.
- not A invierte el valor de verdad.
edad = 25 tiene_carne = True if edad >= 18 and tiene_carne: print("Puede conducir")
[PYTHON]andyorson operadores de cortocircuito (short-circuit).A and BevalúaA; siAes falsy, devuelveAsin evaluarB.A or BevalúaA; siAes truthy, devuelveAsin evaluarB. Esto no solo ahorra tiempo: evita errores cuandoBdepende de queAsea verdadero. Por ejemplo,if lista and lista[0] > 0:es seguro aunque la lista esté vacía, porquelista[0]no se evalúa.
Prioridad: not tiene mayor prioridad que and, y and mayor que or. Cuando mezcles operadores, usa paréntesis para evitar ambigüedades. not a == b se interpreta como not (a == b); a and b or c se interpreta como (a and b) or c.
5.6. Condiciones anidadas
Una condición puede contener otra estructura if dentro de su bloque:
edad = 20 if edad >= 18: if edad >= 65: print("Jubilado") else: print("Adulto en edad laboral") else: print("Menor de edad")
El anidamiento es válido, pero a partir de dos o tres niveles el código se vuelve difícil de leer. PEP 8 y la práctica profesional recomiendan aplanar la lógica cuando sea posible.
[BUENA PRÁCTICA] “Flat is better than nested” es uno de los principios del Zen de Python. Puedes evitar anidamiento combinando condiciones conand/oro usando cláusulas de guarda (guard clauses): comprobar primero los casos excepcionales y salir pronto. En este módulo, con programas pequeños, el anidamiento rara vez es necesario; cuando aparezca, pregúntate si puedes reescribirlo conelif.
La versión aplanada del ejemplo anterior:
if edad < 18: print("Menor de edad") elif edad >= 65: print("Jubilado") else: print("Adulto en edad laboral")
5.7. Expresión condicional: `x if C else y`
Python ofrece una forma compacta de elegir entre dos valores según una condición:
edad = 20 estado = "adulto" if edad >= 18 else "menor" print(estado) # adulto
La expresión x if C else y evalúa primero C; si es verdadera, devuelve x; si es falsa, devuelve y. Es útil para asignaciones simples y para argumentos de funciones, pero no sustituye a un if/elif/else cuando hay más de dos ramas o cuando los bloques tienen varias instrucciones.
[ERROR HABITUAL] Usar la expresión condicional para lógica compleja.resultado = a if c1 else b if c2 else des válido, pero ilegible. Si necesitas más de una condición, usaif/elif/else.
5.8. Valores verdaderos y falsos en la práctica
Aprovecha la truthiness para escribir código más limpio:
| En lugar de… | Escribe… |
|---|---|
if len(nombre) > 0: | if nombre: |
if len(lista) == 0: | if not lista: |
if x != None: | if x is not None: (más explícito y correcto) |
if flag == True: | if flag: |
if flag == False: | if not flag: |
[BUENA PRÁCTICA] PEP 8 y las guías de estilo recomiendan no comparar booleanos con==ois; usa el valor directamente. ParaNone, usa siempreisois not, nunca==.x == Nonepuede serTruepara objetos que sobrecargan__eq__, mientras quex is Nonecomprueba identidad y es inequívoco.
5.9. `match`/`case`: comparaciones múltiples sobre un mismo valor
Introducido en Python 3.10 mediante PEP 634, match/case permite comparar un valor contra varios patrones y ejecutar el primer bloque que coincida. Es más potente que un switch tradicional porque puede desestructurar secuencias, mapeos y objetos, y enlazar variables en el proceso.
La forma más simple compara literales:
codigo = 404 match codigo: case 200: print("OK") case 404: print("No encontrado") case _: print("Otro código")
Reglas básicas:
- match recibe una expresión sujeto (el valor a comparar) y termina en :.
- Cada case define un patrón y termina en :.
- El patrón _ (guion bajo) es un comodín que coincide con cualquier valor y nunca falla.
- Solo se ejecuta el primer case que coincide; los demás se ignoran.
- Si ningún case coincide y no hay _, no se ejecuta ningún bloque.
[PYTHON]matchno es exactamente unswitch: es pattern matching estructural. Puede comprobar la forma de los datos, no solo la igualdad. Por ejemplo,case [x, y]:coincide con una lista de exactamente dos elementos y enlazaxeya sus valores. Esta capacidad se explorará con detalle en el Módulo 8, cuando conozcas las colecciones. Por ahora basta con los patrones literales y el comodín.
[AMPLIACIÓN] En Python 3.15 se ha eliminado una restricción dematch: ahora se permite el signo más unario en los patrones numéricos, de modo quecase +1:es válido (antes solo se aceptabacase -1:). El valor+1es simplemente1, así que el comportamiento no cambia; la mejora es de legibilidad cuando se alinean casos con signos.
5.10. Casos límite y errores lógicos
Las condiciones son propensas a errores que no producen excepciones: el programa se ejecuta, pero decide mal. Los más frecuentes:
- Usar = en lugar de ==: if x = 5: es un SyntaxError en Python (la asignación no es una expresión), así que al menos falla ruidosamente. Pero if x == 5: cuando querías asignar es un error lógico silencioso.
- Ramas inalcanzables: como se ha visto, un elif después de una condición más general nunca se ejecuta.
- Condiciones mal negadas: if not x > 0: es correcto pero confuso; if x <= 0: es más claro.
- Confundir and con or: if edad >= 18 or tiene_carne: autoriza a cualquiera que cumpla una de las dos, no a quien cumpla ambas.
- Olvidar el caso else: si ninguna condición se cumple y no hay else, el programa continúa sin hacer nada. A veces es lo deseado; a veces es un olvido.
[ERROR HABITUAL] Probar solo el caso “feliz”. Un programa que clasifica edades parece correcto hasta que alguien introduce-5o200. Antes de dar por buena una estructura condicional, pregúntate: ¿qué pasa con el valor mínimo, el máximo, el cero, el vacío y el valor inesperado?
6. Ejemplos comentados
Ejemplo 1: Clasificación con if/elif/else.
# archivo: clasificar.py edad = int(input("Introduce tu edad: ")) if edad < 0: print("La edad no puede ser negativa.") elif edad < 13: print("Infancia") elif edad < 18: print("Adolescencia") elif edad < 65: print("Adultez") else: print("Jubilación")
Seguimiento: Si edad es 10, la primera condición (< 0) es falsa, la segunda (< 13) es verdadera y se ejecuta "Infancia". Las demás ramas no se evalúan. Si edad es 70, se recorren todas las condiciones hasta que edad < 65 es falsa, y se ejecuta el else.
Ejemplo 2: Condición compuesta y cortocircuito.
# archivo: acceso.py nombre = input("Nombre: ").strip() clave = input("Contraseña: ") if nombre and clave == "secreto": print(f"Bienvenido, {nombre}.") else: print("Acceso denegado.")
Predicción: Si el usuario deja el nombre vacío y escribe "secreto", nombre es "" (falsy). nombre and clave == "secreto" devuelve "" sin evaluar la segunda parte, y el if lo trata como falso. Se muestra “Acceso denegado”. Si el nombre no está vacío pero la clave es incorrecta, la segunda parte se evalúa y también da falso.
Ejemplo 3: match/case con literales.
# archivo: menu.py opcion = input("Elige una opción (1-3): ") match opcion: case "1": print("Has elegido consultar saldo.") case "2": print("Has elegido transferir.") case "3": print("Has elegido salir.") case _: print("Opción no válida.")
Seguimiento: input() devuelve un str, así que los patrones son cadenas ("1", no 1). El comodín _ captura cualquier otra entrada, incluidas cadenas vacías o letras.
7. Seguimiento de la ejecución
Cuando Python encuentra una estructura if/elif/else, sigue este orden:
1. Evalúa la condición del if. Si es verdadera, ejecuta su bloque y salta al final de toda la estructura.
2. Si es falsa, evalúa la condición del primer elif. Si es verdadera, ejecuta su bloque y salta al final.
3. Repite con cada elif en orden.
4. Si ninguna condición se cumple y hay un else, ejecuta su bloque.
5. Si no hay else, no ejecuta ningún bloque.
6. Continúa con la primera instrucción no indentada después de la estructura.
Este comportamiento de “una sola rama” es fundamental: a diferencia de una serie de if independientes, una estructura if/elif/else garantiza que como máximo se ejecute un bloque.
8. Errores habituales
| Error | Causa | Cómo diagnosticarlo |
|---|---|---|
SyntaxError por falta de : | Olvidar los dos puntos en if, elif, else o case. | Revisa la línea que señala el mensaje; añade : al final. |
IndentationError: expected an indented block | El bloque del if no está indentado. | Añade 4 espacios en las líneas del bloque. |
IndentationError: unexpected indent | Una línea está indentada sin que haya una estructura que lo justifique. | Elimina la indentación sobrante. |
| Rama inalcanzable | Un elif está después de una condición más general. | Reordena las condiciones o combínalas. |
if x = 5: | Usar asignación en lugar de comparación. | SyntaxError en Python; usa == para comparar. |
if x == None: | Comparar None con ==. | Usa if x is None: (PEP 8). |
if flag == True: | Comparar un booleano con ==. | Usa if flag: directamente. |
[ERROR HABITUAL] El error lógico más difícil de detectar no produce mensaje: la condición es sintácticamente válida pero no expresa lo que pretendías. Para detectarlo, prueba el programa con valores representativos (positivo, negativo, cero, vacío) y comprueba que cada rama se ejecuta cuando debería.
9. Particularidades de Python frente a otros lenguajes
- elif en lugar de else if: Python usa una palabra clave propia para evitar el anidamiento excesivo de else: if:. En C o Java, else if es una convención; en Python, elif es parte de la sintaxis.
- Indentación obligatoria: en C o Java, un if sin llaves ejecuta solo la siguiente instrucción; en Python, el bloque se define por la indentación. Esto elimina la ambigüedad del “if colgante” (dangling else) y hace que la estructura sea visualmente evidente.
- Truthiness: en Java, una condición debe ser boolean; en Python, cualquier objeto se evalúa como verdadero o falso. Esto permite escribir if lista: en lugar de if lista.size() > 0, pero exige entender qué se está evaluando.
- match/case: no es un switch de C. Es pattern matching estructural, que puede desestructurar datos y enlazar variables. Un switch de C solo compara valores enteros; match puede comparar formas, tipos y atributos.
10. Buenas prácticas
Incorrecto (condiciones redundantes y comparaciones innecesarias):
if es_mayor == True: if len(nombre) > 0: print("Acceso permitido")
Mejor:
if es_mayor and nombre: print("Acceso permitido")
[BUENA PRÁCTICA] Aprovecha la truthiness para las colecciones y los booleanos, pero sé explícito conNone(is None/is not None). Evita el anidamiento innecesario: combina condiciones conand/oro usaelif. Ordena las ramas de la más específica a la más general. Y usamatch/casecuando compares un mismo valor contra varios literales o patrones, porque suele ser más legible que una cadena larga deelif.
11. Windows y Linux
Las estructuras condicionales son idénticas en Windows y Linux. La sintaxis, la indentación y el comportamiento de match son los mismos. Las diferencias operativas (comando py frente a python3, finales de línea) ya las conoces de módulos anteriores y no afectan al código condicional.
[WINDOWS / LINUX] Si escribesinput()y el usuario introduce una letra en lugar de un número,int()lanzaráValueErroren ambos sistemas. La validación conisdigit()o contry/except(Módulo 11) es portable. En este módulo, asume que la entrada es válida para centrarte en la lógica condicional.
12. Ejercicios guiados
Ejercicio guiado 1: Clasificar un número.
Escribe un programa que pida un número entero y muestre:
- "Negativo" si es menor que 0.
- "Cero" si es exactamente 0.
- "Positivo" si es mayor que 0.
1. Predice qué rama se ejecutará para -3, 0 y 7.
2. Escribe el código con if/elif/else.
3. Ejecútalo con esos tres valores y comprueba tus predicciones.
Ejercicio guiado 2: Año bisiesto (simplificado).
Un año es bisiesto si es divisible entre 4, pero no entre 100, salvo que sea divisible entre 400. Escribe un programa que pida un año y muestre "Bisiesto" o "No bisiesto".
Pista: usa el operador % para comprobar la divisibilidad. Construye la condición con and/or y paréntesis.
Ejercicio guiado 3: match para un menú.
Escribe un programa que pida una letra ("a", "b" o "c") y use match/case para mostrar un mensaje distinto para cada una, y "Opción desconocida" para cualquier otra. Prueba con mayúsculas y minúsculas: ¿qué ocurre si el usuario escribe "A"?
13. Ejercicios autónomos
1. Predicción: Sin ejecutar, determina qué muestra cada estructura.
```python
x = 5
if x > 0:
print("A")
elif x > 3:
print("B")
else:
print("C")
```
```python
x = 0
if x:
print("Verdadero")
else:
print("Falso")
```
2. Corrección: El siguiente código no hace lo que se espera (clasificar como “adulto” si la edad es 18 o más). Encuentra el error lógico y corrígelo:
```python
edad = 20
if edad > 18:
print("Adulto")
else:
print("Menor")
```
3. Condición compuesta: Pide una temperatura y una humedad. Muestra "Calor y húmedo" si la temperatura es mayor de 30 y la humedad mayor del 60 %. En caso contrario, muestra "Condiciones normales".
4. Expresión condicional: Reescribe esta estructura con una expresión condicional:
```python
if nota >= 5:
resultado = "Aprobado"
else:
resultado = "Suspenso"
```
5. Reto opcional: Investiga en la documentación oficial qué es el pattern matching estructural y escribe un ejemplo de match que use un patrón de secuencia (por ejemplo, case [x, y]:) con una lista de dos elementos. No necesitas entender todos los detalles; solo comprobar que Python ejecuta el caso correcto.
14. Soluciones razonadas
Solución al ejercicio guiado 1:
numero = int(input("Introduce un número entero: ")) if numero < 0: print("Negativo") elif numero == 0: print("Cero") else: print("Positivo")
Para -3 se ejecuta “Negativo”; para 0, “Cero”; para 7, “Positivo”. La estructura garantiza que solo se ejecuta una rama.
Solución al ejercicio guiado 2:
anio = int(input("Introduce un año: ")) if (anio % 4 == 0 and anio % 100 != 0) or (anio % 400 == 0): print("Bisiesto") else: print("No bisiesto")
Los paréntesis agrupan las dos condiciones principales: “divisible entre 4 y no entre 100” o “divisible entre 400”. Sin paréntesis, or y and se evaluarían con la prioridad estándar y el resultado sería incorrecto.
Solución al ejercicio guiado 3:
opcion = input("Elige a, b o c: ").lower() match opcion: case "a": print("Has elegido la opción A.") case "b": print("Has elegido la opción B.") case "c": print("Has elegido la opción C.") case _: print("Opción desconocida.")
.lower() normaliza la entrada para que "A" coincida con "a". Sin él, "A" caería en el comodín _. Este es un ejemplo de cómo la manipulación de texto del Módulo 5 se combina con las decisiones de este módulo.
Solución al ejercicio 1 (predicción):
- Primer bloque: x = 5. x > 0 es verdadero, así que se ejecuta "A" y se ignora el elif. Aunque x > 3 también es verdadero, la rama no se evalúa.
- Segundo bloque: x = 0 es falsy, así que se ejecuta el else y muestra "Falso".
Solución al ejercicio 2 (corrección):
El error es edad > 18: con edad = 18, la condición es falsa y se clasifica como “Menor”. Debe ser edad >= 18. Este es un caso límite clásico.
Solución al ejercicio 3 (condición compuesta):
temperatura = float(input("Temperatura: ")) humedad = float(input("Humedad (%): ")) if temperatura > 30 and humedad > 60: print("Calor y húmedo") else: print("Condiciones normales")
Solución al ejercicio 4 (expresión condicional):
resultado = "Aprobado" if nota >= 5 else "Suspenso"
15. Resumen
- Una condición es cualquier expresión que Python evalúa como verdadera o falsa. Cualquier objeto puede usarse; los valores falsy incluyen None, False, cero y colecciones vacías.
- if ejecuta un bloque si la condición es verdadera; else cubre el caso contrario; elif permite comprobar condiciones adicionales en orden.
- and, or y not combinan condiciones, con cortocircuito: and no evalúa el segundo operando si el primero es falsy, y or no lo evalúa si el primero es truthy.
- El anidamiento es válido pero debe evitarse cuando pueda sustituirse por elif o por condiciones compuestas.
- La expresión x if C else y elige entre dos valores en una sola línea; no sustituye a if/elif para lógica compleja.
- match/case compara un valor contra patrones y ejecuta el primero que coincide; _ es el comodín. Es más potente que un switch porque puede desestructurar datos.
- Los errores lógicos en condiciones no producen excepciones: prueba con valores límite (cero, negativo, vacío) para detectarlos.
16. Autoevaluación
1. ¿Qué diferencia hay entre una serie de if independientes y una estructura if/elif/else?
2. ¿Por qué if lista: es equivalente a if len(lista) > 0:? ¿Y por qué if x is not None: no es equivalente a if x:?
3. ¿Qué significa que and y or hagan cortocircuito? Pon un ejemplo en el que el cortocircuito evite un error.
4. ¿Cuándo usarías match/case en lugar de if/elif?
5. Reto: Sin ejecutar, predice qué muestra este código y explica por qué:
```python
x = 10
if x > 5:
print("Grande")
elif x > 8:
print("Muy grande")
else:
print("Pequeño")
```
