8. Tomar decisiones con sentencias if
En los programas que hemos escrito hasta ahora, Python ejecuta cada línea de código de arriba abajo, una sentencia tras otra. Pero los programas del mundo real necesitan tomar decisiones: ejecutar código diferente según distintas condiciones. ¿Deberíamos mostrar un mensaje de error? ¿Deberíamos calcular un descuento? ¿Deberíamos pedir la entrada de nuevo? La respuesta depende de la situación.
Las sentencias condicionales (conditional statements) permiten que tus programas tomen estas decisiones. Permiten que Python ejecute ciertos bloques de código solo cuando condiciones específicas son verdaderas, y los omita en caso contrario. Este capítulo presenta la sentencia if de Python y sus variaciones, que forman la base de la toma de decisiones en tus programas.
Al dominar las sentencias condicionales, podrás escribir programas que respondan inteligentemente a la entrada del usuario, manejen distintos escenarios de forma apropiada y resuelvan problemas que requieren razonamiento lógico.
8.1) Sentencias if simples
La forma más básica de tomar decisiones en Python es la sentencia if simple. Le dice a Python: “Si esta condición es verdadera, ejecuta este bloque de código. Si no, omítelo y continúa”.
8.1.1) La estructura de una sentencia if
Aquí tienes la sintaxis básica de una sentencia if:
if condition:
# Código a ejecutar si condition es True
statement1
statement2
# ... más sentenciasDesglosemos cada parte:
- La palabra clave
if: Esto inicia la sentencia condicional - La condición: Una expresión booleana que se evalúa como
TrueoFalse(del Capítulo 7) - Los dos puntos (
:): Son obligatorios y marcan el final de la línea de la condición - El bloque de código con sangría: Todas las sentencias con sangría bajo el
ifse ejecutan solo cuando la condición esTrue
La sangría es crítica en Python. Las líneas con sangría forman un bloque de código que pertenece a la sentencia if. Python usa la sangría (normalmente 4 espacios) para determinar qué sentencias forman parte del bloque condicional.
Aquí tienes un ejemplo sencillo:
# temperature_check.py
temperature = 30
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # Esto siempre se ejecutaOutput:
It's a warm day!
Consider wearing light clothing.
Have a great day!En este ejemplo:
- La condición
temperature > 25se evalúa comoTrue(ya que 30 > 25) - Ambas sentencias
print()con sangría se ejecutan porque forman parte del bloqueif - La sentencia
print()final siempre se ejecuta porque no tiene sangría; no forma parte del bloqueif
Ahora veamos qué pasa cuando la condición es False:
# temperature_check_cool.py
temperature = 18
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # Esto siempre se ejecutaOutput:
Have a great day!Esta vez:
- La condición
temperature > 25se evalúa comoFalse(ya que 18 no es mayor que 25) - Ambas sentencias con sangría se omiten por completo
- Solo se ejecuta el
print()final porque está fuera del bloqueif
8.1.2) Usar condiciones del Capítulo 7
Cualquier expresión booleana del Capítulo 7 puede usarse como condición en una sentencia if. Esto incluye:
Operadores de comparación:
# voting_eligibility.py
age = 16
if age >= 18:
print("You are eligible to vote.")
# Nada se imprime porque 16 >= 18 es False
score = 85
if score >= 60:
print("You passed the exam!") # Output: You passed the exam!Pruebas de pertenencia con in y not in:
# user_access.py
username = "alice"
banned_users = ["bob", "charlie", "dave"]
if username not in banned_users:
print(f"Welcome, {username}!") # Output: Welcome, alice!
favorite_color = "blue"
if "u" in favorite_color:
print("Your favorite color contains the letter 'u'.") # Output: Your favorite color contains the letter 'u'.Valores booleanos directos:
# weather_check.py
is_raining = True
if is_raining:
print("Don't forget your umbrella!") # Output: Don't forget your umbrella!Valores truthy y falsy (del Capítulo 7.4):
# name_input.py
user_input = input("Enter your name: ")
if user_input: # La cadena vacía es falsy, una cadena no vacía es truthy
print(f"Hello, {user_input}!")
else:
print("You didn't enter a name.")8.1.3) Múltiples sentencias en el bloque if
Puedes incluir tantas sentencias como necesites en un bloque if. Todas las sentencias con sangría bajo la línea if pertenecen a ese bloque:
# bank_withdrawal.py
balance = 1500
withdrawal = 200
if withdrawal <= balance:
balance = balance - withdrawal # Restar withdrawal del balance
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # Siempre se ejecutaOutput:
Withdrawal successful!
Your new balance is: $1300
Thank you for your transaction.
Transaction complete.Las cuatro sentencias se ejecutan porque withdrawal <= balance es True. Si cambiamos el retiro a 2000:
# bank_withdrawal_insufficient.py
balance = 1500
withdrawal = 2000
if withdrawal <= balance:
balance = balance - withdrawal
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # Siempre se ejecutaOutput:
Transaction complete.Ahora ninguna de las sentencias con sangría se ejecuta porque la condición es False. El saldo permanece sin cambios en 1500.
8.2) Usar if-else para elecciones de sí o no
A menudo necesitas elegir entre dos alternativas: ejecutar un bloque de código si una condición es verdadera, y un bloque diferente si es falsa. La sentencia if-else maneja esta toma de decisiones de tipo sí-o-no.
8.2.1) La estructura de if-else
Aquí tienes la sintaxis:
if condition:
# Código a ejecutar si condition es True
statement1
statement2
else:
# Código a ejecutar si condition es False
statement3
statement4La cláusula else proporciona una ruta alternativa. Exactamente uno de los dos bloques se ejecutará: nunca ambos, nunca ninguno.
Veamos un ejemplo práctico:
# age_verification.py
age = int(input("Enter your age: "))
if age >= 18:
print("You are an adult.")
print("You can vote in elections.")
else:
print("You are a minor.")
print("You cannot vote yet.")
print("Thank you for providing your age.")Si introduces 25:
You are an adult.
You can vote in elections.
Thank you for providing your age.Si introduces 15:
You are a minor.
You cannot vote yet.
Thank you for providing your age.Fíjate en que exactamente uno de los dos bloques se ejecuta, dependiendo de la condición. La sentencia print() final siempre se ejecuta porque está fuera de ambos bloques.
8.2.2) Tomar decisiones binarias
if-else es perfecto para decisiones binarias donde hay exactamente dos posibles resultados:
# even_odd_checker.py
number = int(input("Enter a number: "))
if number % 2 == 0:
print(f"{number} is even.")
else:
print(f"{number} is odd.")# password_verification.py
stored_password = "python123"
entered_password = input("Enter password: ")
if entered_password == stored_password:
print("Access granted.")
print("Welcome to the system!")
else:
print("Access denied.")
print("Incorrect password.")8.3) Múltiples opciones con if-elif-else
Las decisiones del mundo real a menudo implican más de dos opciones. ¿Deberíamos cobrar envío estándar, envío exprés o envío nocturno? ¿Es una nota una A, B, C, D o F? La cadena if-elif-else maneja múltiples alternativas mutuamente excluyentes.
8.3.1) La estructura de if-elif-else
Aquí tienes la sintaxis:
if condition1:
# Ejecutar si condition1 es True
block1
elif condition2:
# Ejecutar si condition1 es False y condition2 es True
block2
elif condition3:
# Ejecutar si condition1 y condition2 son False, y condition3 es True
block3
else:
# Ejecutar si todas las condiciones son False
block4Puntos clave sobre las cadenas if-elif-else:
elifes la abreviatura de "else if": Proporciona condiciones adicionales que comprobar- El orden importa: Python comprueba las condiciones de arriba abajo
- La primera coincidencia gana: En cuanto una condición es
True, ese bloque se ejecuta y el resto se omite - Exactamente un bloque se ejecuta: Como máximo, se ejecutará un bloque en la cadena
elsees opcional: Captura todos los casos no manejados por las condiciones anteriores
Veamos un ejemplo práctico:
# grade_calculator.py
score = int(input("Enter your exam score (0-100): "))
if score >= 90:
grade = "A"
print("Excellent work!")
elif score >= 80:
grade = "B"
print("Good job!")
elif score >= 70:
grade = "C"
print("Satisfactory.")
elif score >= 60:
grade = "D"
print("You passed, but consider reviewing the material.")
else:
grade = "F"
print("Unfortunately, you did not pass.")
print(f"Your grade is: {grade}")Si introduces 85:
Good job!
Your grade is: BSigamos el rastro de lo que ocurre:
- Comprobar
score >= 90: False (85 no es >= 90), así que omite este bloque - Comprobar
score >= 80: True (85 >= 80), así que ejecuta este bloque - Omitir todos los
elifyelserestantes porque ya encontramos una coincidencia
Si introduces 55:
Unfortunately, you did not pass.
Your grade is: FTodas las condiciones son False, así que se ejecuta el bloque else.
8.3.2) Por qué el orden importa en cadenas elif
El orden de las condiciones es crucial porque Python deja de comprobar en cuanto encuentra una condición True. Considera este sistema de calificación incorrecto:
# ORDEN INCORRECTO - ¡No hagas esto!
score = 85
if score >= 60: # ¡Esto coincidirá primero!
grade = "D"
elif score >= 70:
grade = "C"
elif score >= 80:
grade = "B"
elif score >= 90:
grade = "A"
else:
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: D¡Esto da un resultado incorrecto! La puntuación 85 debería ser una B, pero obtiene una D porque score >= 60 se comprueba primero y es True. Python nunca llega a la condición score >= 80.
Ordena siempre las condiciones de la más específica a la menos específica:
# ORDEN CORRECTO
score = 85
if score >= 90: # La más específica
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else: # La menos específica
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: B8.3.3) Usar elif sin else
La cláusula else es opcional. A veces solo quieres manejar casos específicos y no hacer nada con los demás:
# weekend_checker.py
day = input("Enter a day of the week: ").lower()
if day == "saturday" or day == "sunday":
print("It's the weekend! Time to relax.")
elif day == "friday":
print("It's Friday! The weekend is almost here.")
elif day in ["monday", "tuesday", "wednesday", "thursday"]:
print("It's a weekday. Time to work or study.")
# Sin cláusula else: si no coincide ninguna, no pasa nada
print("Have a great day!")Si introduces "holiday":
Have a great day!No se cumplió ninguna condición, y no hay cláusula else, así que solo se ejecuta el print() final.
8.4) Sentencias if anidadas
A veces necesitas tomar una decisión dentro de otra decisión. Las sentencias if anidadas colocan un condicional dentro de otro, permitiéndote comprobar condiciones adicionales solo después de que se cumpla una condición inicial.
8.4.1) Comprender los condicionales anidados
Las sentencias if anidadas son potentes porque te permiten evitar comprobar condiciones que todavía no tienen sentido. Por ejemplo, no tiene sentido pedir una contraseña si el usuario no tiene una cuenta. La anidación te permite estructurar tu lógica para que coincida con procesos de toma de decisiones del mundo real donde algunas preguntas solo tienen sentido después de que otras se respondan.
Una sentencia if anidada es simplemente una sentencia if (o una cadena if-elif-else) dentro de otro bloque if:
if outer_condition:
# Este código se ejecuta si outer_condition es True
if inner_condition:
# Este código se ejecuta si AMBAS condiciones son True
inner_block
else:
# Esto se ejecuta si outer_condition es True pero inner_condition es False
inner_else_block
else:
# Esto se ejecuta si outer_condition es False
outer_else_blockLa sentencia if interna solo se evalúa si la condición externa es True. Esto crea una jerarquía de decisiones.
Aquí tienes un ejemplo sencillo:
# account_login.py
has_account = input("Do you have an account? (yes/no): ").lower() == "yes"
if has_account:
print("Welcome back!")
password = input("Enter your password: ")
if password == "secret123":
print("Login successful!")
print("Access granted to your dashboard.")
else:
print("Incorrect password.")
print("Access denied.")
else:
print("Please create an account first.")
print("Visit our registration page.")Si respondes "yes" e introduces la contraseña correcta:
Welcome back!
Login successful!
Access granted to your dashboard.Si respondes "yes" pero introduces una contraseña incorrecta:
Welcome back!
Incorrect password.
Access denied.Si respondes "no":
Please create an account first.
Visit our registration page.Fíjate en que la comprobación de la contraseña solo ocurre si el usuario tiene una cuenta. Este es el beneficio clave de la anidación: puedes evitar comprobaciones innecesarias.
8.4.2) Cuándo usar sentencias if anidadas
Las sentencias if anidadas son útiles cuando:
- Las decisiones dependen de decisiones previas: Necesitas comprobar algo solo después de que se cumpla otra condición
- Crear árboles de decisión: Cada nivel reduce las posibilidades
- Validar requisitos previos: Comprueba requisitos básicos antes de comprobar requisitos detallados
- Evitar comprobaciones innecesarias: Omite operaciones costosas cuando condiciones anteriores fallan
Ejemplo: elegibilidad para un préstamo
# loan_eligibility.py
age = int(input("Enter your age: "))
if age >= 18:
print("Age requirement met.")
income = float(input("Enter your annual income: $"))
if income >= 30000:
print("Income requirement met.")
credit_score = int(input("Enter your credit score: "))
if credit_score >= 650:
print("Congratulations! You are eligible for a loan.")
print("Please proceed to the application form.")
else:
print("Sorry, your credit score is too low.")
print("Minimum required: 650")
else:
print("Sorry, your income is too low.")
print("Minimum required: $30,000")
else:
print("Sorry, you must be 18 or older to apply.")Esto crea un árbol de decisiones donde cada nivel depende del anterior. Si la edad es menor de 18, nunca preguntamos por los ingresos ni por el puntaje crediticio.
8.4.3) Evitar un exceso de anidación
Aunque la anidación es potente, demasiados niveles hacen que el código sea difícil de leer y entender. Considera este ejemplo muy anidado:
# Demasiado anidado: difícil de seguir
if condition1:
if condition2:
if condition3:
if condition4:
if condition5:
print("All conditions met!")Esto es difícil de leer y mantener. Aquí tienes estrategias para reducir la anidación:
Estrategia 1: Combinar condiciones cuando sea apropiado
Aprenderemos sobre el operador and en detalle en el Capítulo 9, pero por ahora, solo ten en cuenta que te permite comprobar múltiples condiciones a la vez:
# Mejor: usar 'and' para combinar condiciones (el Capítulo 9 explicará esto completamente)
# Aprenderemos sobre 'and' en el Capítulo 9, pero por ahora, solo ten en cuenta que comprueba
# que todas las condiciones sean verdaderas
if condition1 and condition2 and condition3 and condition4 and condition5:
print("All conditions met!")Estrategia 2: Usar retornos tempranos (cuando trabajes con funciones, que aprenderemos en el Capítulo 19):
# En una función, podemos hacer return temprano
def check_eligibility(age, income, credit_score):
if age < 18:
return "Too young"
if income < 30000:
return "Income too low"
if credit_score < 650:
return "Credit score too low"
return "Eligible"Estrategia 3: Aplanar con elif cuando sea apropiado:
# En lugar de if anidados que comprueban rangos
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
# ... y así sucesivamente8.5) Errores comunes con sentencias if (sangría, dos puntos y lógica)
Incluso los programadores con experiencia cometen errores con sentencias if. Esta sección cubre los errores más comunes que encuentran los principiantes y cómo evitarlos.
8.5.1) Errores de sangría
Python usa la sangría para determinar qué sentencias pertenecen a qué bloque. La sangría incorrecta es una de las fuentes de errores más comunes.
Problema 1: Falta de sangría
# INCORRECTO - IndentationError
age = 20
if age >= 18:
print("You are an adult.") # ¡Sin sangría!Esto produce:
File "example.py", line 4
print("You are an adult.")
^
IndentationError: expected an indented blockSolución: Siempre aplica sangría al bloque bajo una sentencia if:
# CORRECTO
age = 20
if age >= 18:
print("You are an adult.") # Con sangría correctaProblema 2: Sangría inconsistente
# INCORRECTO - Mezclando espacios y tabulaciones, o espacios inconsistentes
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # Espacios extra: sangría inconsistenteSolución: Usa una sangría consistente (4 espacios es el estándar de Python):
# CORRECTO
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # Mismo nivel de sangríaProblema 3: Sangría incorrecta en anidación
# INCORRECTO - Nivel de sangría incorrecto
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # Debería tener más sangríaSolución: Cada nivel anidado necesita sangría adicional:
# CORRECTO
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # Con sangría adecuada para el bloque anidado8.5.2) Falta de dos puntos
Los dos puntos (:) al final de las líneas if, elif y else son obligatorios. Olvidarlos es un error muy común:
# INCORRECTO - SyntaxError: missing colon
if age >= 18
print("Adult")Esto produce:
File "example.py", line 2
if age >= 18
^
SyntaxError: invalid syntaxSolución: Incluye siempre los dos puntos:
# CORRECTO
if age >= 18:
print("Adult")Lo mismo se aplica a elif y else:
# CORRECTO - Todos los dos puntos presentes
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "F"8.5.3) Operadores de comparación incorrectos
Problema 1: Usar asignación (=) en lugar de comparación (==)
# INCORRECTO - ¡Esto asigna 18 a age, no compara!
age = 20
if age = 18: # SyntaxError
print("You are 18")Solución: Usa == para comparar:
# CORRECTO
age = 20
if age == 18:
print("You are 18")8.5.4) Código inalcanzable debido a errores lógicos
Problema: Condiciones que nunca pueden ser True
# INCORRECTO - El elif nunca puede ejecutarse
score = 85
if score >= 60:
print("You passed!")
elif score >= 80: # ¡Esto nunca se ejecutará!
print("You got a B!")Si score es 85, la primera condición (score >= 60) es True, así que el elif nunca se comprueba. El orden es incorrecto.
Solución: Ordena las condiciones de la más específica a la menos específica:
# CORRECTO
score = 85
if score >= 80:
print("You got a B!")
elif score >= 60:
print("You passed!")8.5.5) Bloques if vacíos
No puedes tener un bloque if vacío en Python:
# INCORRECTO - SyntaxError
if temperature > 30:
# Añadiré código aquí más tarde
print("Done")Esto produce:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented blockSolución: Usa la sentencia pass como marcador de posición (se cubre en la siguiente sección):
# CORRECTO - Usar pass como marcador de posición
if temperature > 30:
pass # TODO: Añadir código aquí más tarde
print("Done")8.6) Usar pass como marcador de posición en bloques
A veces, al escribir código, sabes que necesitas una sentencia if pero todavía no has decidido qué código debe ir dentro. Python no permite bloques de código vacíos, así que necesitas una forma de crear un bloque válido pero que “no haga nada”. Ahí es donde entra la sentencia pass.
8.6.1) ¿Qué es pass?
La sentencia pass es una operación nula: cuando Python la ejecuta, no sucede nada. Es un marcador de posición que te permite escribir código sintácticamente correcto incluso cuando todavía no tienes la implementación lista.
if condition:
pass # No hacer nada por ahoraPiensa en pass como una forma de decirle a Python: “Sé que necesito código aquí, pero lo completaré más tarde”. Es especialmente útil durante el desarrollo, cuando estás esbozando la estructura de tu programa.
8.6.2) Por qué pass es necesario
Python requiere al menos una sentencia en cada bloque de código. Un bloque vacío causa un error de sintaxis:
# INCORRECTO - Esto provoca un error
if age >= 18:
# TODO: Añadir aquí la lógica de adulto
print("Done")Error:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented blockUsar pass hace que el código sea sintácticamente válido:
# CORRECTO - Usar pass como marcador de posición
if age >= 18:
pass # TODO: Añadir aquí la lógica de adulto
print("Done")8.6.3) Usos comunes de pass
Uso 1: Marcador de posición durante el desarrollo
Cuando estás delineando la estructura de tu programa pero todavía no has implementado todo:
# user_system.py
user_type = input("Enter user type (admin/user/guest): ").lower()
if user_type == "admin":
pass # TODO: Implementar funciones de admin
elif user_type == "user":
pass # TODO: Implementar funciones de user
elif user_type == "guest":
print("Welcome, guest! Limited access granted.")
else:
print("Invalid user type.")Esto te permite ejecutar el programa y probar las partes que ya has implementado, dejando marcadores de posición para trabajo futuro.
Uso 2: No hacer nada intencionalmente en una rama
A veces realmente quieres no hacer nada en ciertos casos, pero necesitas manejar otros casos:
# positive_numbers.py
# Procesar solo números positivos
number = int(input("Enter a number: "))
if number > 0:
result = number * 2
print(f"Double of {number} is {result}")
elif number == 0:
pass # Cero es válido pero no requiere ninguna acción
else:
print("Negative numbers are not allowed.")8.6.4) pass en otros contextos
Aunque hemos centrado pass en sentencias if, lo encontrarás en otros contextos a medida que aprendas más Python:
- Funciones (Chapter 20): Placeholder for function bodies
- Clases (Chapter 31): Placeholder for class definitions
- Bucles (Chapters 11-12): Placeholder for loop bodies
- Manejadores de excepciones (Chapter 29): Intentionally ignoring errors
Por ahora, recuerda que pass es tu herramienta para crear bloques de código válidos pero vacíos cuando los necesites.
Integrándolo todo
En este capítulo, has aprendido a hacer que tus programas sean inteligentes y respondan usando sentencias condicionales. Repasemos los conceptos clave:
Las sentencias if simples ejecutan código solo cuando una condición es verdadera:
if temperature > 30:
print("It's hot outside!")Las sentencias if-else eligen entre dos alternativas:
if age >= 18:
print("Adult")
else:
print("Minor")Las cadenas if-elif-else manejan múltiples opciones mutuamente excluyentes:
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"Las sentencias if anidadas toman decisiones dentro de decisiones:
if has_account:
if password_correct:
print("Welcome!")
else:
print("Wrong password")
else:
print("Create an account")Errores comunes que debes evitar:
- Olvidar los dos puntos después de
if,elifyelse - Sangría incorrecta o inconsistente
- Usar
=en lugar de==para comparar - Orden incorrecto en cadenas
elif - Bloques vacíos sin
pass
La sentencia pass sirve como marcador de posición para bloques vacíos durante el desarrollo.
Ahora tienes las herramientas para escribir programas que tomen decisiones inteligentes basadas en condiciones. En el próximo capítulo, aprenderemos sobre operadores de lógica booleana (and, or, not) que te permiten combinar múltiples condiciones en una lógica de toma de decisiones más sofisticada. Esto hará que tus sentencias if sean aún más potentes y expresivas.