Al final del módulo anterior dejamos el proyecto Papyrus con su entorno listo y varios scripts funcionando, y prometimos que tus programas empezarían a tomar decisiones. Esta lección cumple esa promesa: aprenderás a usar if, elif y else para que Python ejecute un código u otro según las condiciones que se cumplan. Es la diferencia entre un script que siempre hace lo mismo y un programa que reacciona: "¿hay stock de La Odisea?", "¿Luis es socio? Entonces aplícale el descuento". Sin condicionales no hay lógica de negocio posible, así que esta es probablemente la lección más importante del curso hasta ahora.
Contenido
- La sentencia
if: tomar la primera decisión else: el camino alternativoelif: encadenar varias condiciones- Condicionales anidados
- Condiciones compuestas con
and,orynot - Truthiness: valores que se comportan como
TrueoFalse - El operador ternario: condicionales en una línea
La sentencia if: tomar la primera decisión
La estructura básica de un condicional en Python es la sentencia if (en inglés, "si"). Su sintaxis es:
Fíjate en tres detalles fundamentales:
- La condición es cualquier expresión que Python pueda evaluar como
TrueoFalse(los booleanos que viste en el módulo 1). - Los dos puntos (
:) al final de la línea delifson obligatorios. Olvidarlos es el error de sintaxis más frecuente al empezar. - El bloque indentado (con 4 espacios, como ya sabes por PEP 8) define qué instrucciones dependen del
if. En Python la indentación no es estética: es la estructura del programa.
Vamos a resolver la primera pregunta que Ana se hace cada vez que alguien pide un libro en Papyrus: ¿hay stock?
titulo = "La Odisea"
stock = 4
if stock > 0:
print(f"'{titulo}' está disponible ({stock} unidades).")
print("Consulta finalizada.")Salida:
¿Qué ha pasado exactamente?
- Python evalúa
stock > 0. Comostockvale4, la expresión daTrue. - Al ser verdadera, se ejecuta el bloque indentado (el
printdel mensaje de disponibilidad). - La última línea,
print("Consulta finalizada."), no está indentada, así que no forma parte delif: se ejecuta siempre, haya o no stock.
Si cambias stock = 0 y vuelves a ejecutar, verás solo Consulta finalizada.: el bloque del if se salta por completo.
El flujo de un if, visto como diagrama
flowchart TD
A[Inicio] --> B{stock > 0}
B -- True --> C[Mostrar disponibilidad]
B -- False --> D[Continuar]
C --> D
D --> E[Consulta finalizada]
El programa llega a una bifurcación, elige un camino según la condición y después ambos caminos vuelven a unirse.
else: el camino alternativo
Muchas veces no basta con "haz esto si se cumple": también quieres hacer otra cosa si no se cumple. Para eso existe else ("si no"):
titulo = "Hamlet"
stock = 0
if stock > 0:
print(f"'{titulo}' está disponible ({stock} unidades).")
else:
print(f"'{titulo}' está agotado. Ana debe reponerlo.")Salida:
Reglas de else:
- No lleva condición propia: se ejecuta cuando la condición del
ifes falsa. - Va al mismo nivel de indentación que su
if, también con dos puntos. - Es opcional: un
ifpuede ir perfectamente solo, como en el primer ejemplo.
Con if/else garantizas que exactamente uno de los dos bloques se ejecuta siempre.
elif: encadenar varias condiciones
¿Y si hay más de dos escenarios? Ana quiere clasificar el stock de cada libro en tres niveles: agotado, quedan pocas unidades, o stock suficiente. Para encadenar condiciones se usa elif (contracción de else if):
titulo = "El Quijote"
stock = 8
if stock == 0:
print(f"'{titulo}': AGOTADO. Pedir al distribuidor.")
elif stock <= 3:
print(f"'{titulo}': quedan pocas unidades ({stock}).")
else:
print(f"'{titulo}': stock suficiente ({stock} unidades).")Salida:
Cómo lo evalúa Python, en orden y de arriba abajo:
stock == 0→8 == 0esFalse. Se salta ese bloque.stock <= 3→8 <= 3esFalse. Se salta también.- Ninguna condición se cumplió, así que se ejecuta el
else.
Puntos clave de las cadenas if/elif/else:
- Puedes poner tantos
elifcomo necesites. - En cuanto una condición da
True, se ejecuta su bloque y el resto de la cadena se ignora, aunque otras condiciones también fueran ciertas. El orden importa. - El
elsefinal es opcional, pero suele ser buena idea incluirlo como "caso por defecto".
Ese segundo punto merece un ejemplo. Observa qué pasa si ordenamos mal las condiciones:
stock = 0
# MAL ordenado: la condición amplia va primero
if stock <= 3:
print("Quedan pocas unidades.") # ¡Se ejecuta esto!
elif stock == 0:
print("AGOTADO.") # Nunca se llega aquí con stock 0Con stock = 0, la primera condición (0 <= 3) ya es cierta, así que el mensaje de "AGOTADO" jamás se mostrará. Regla práctica: coloca primero las condiciones más específicas y deja las más generales para el final.
Condicionales anidados
Un bloque if puede contener, a su vez, otro if. Es lo que llamamos anidamiento, y sirve para decisiones que dependen de una decisión anterior. En Papyrus: primero comprobamos si hay stock y, solo si lo hay, comprobamos si el cliente es socio para aplicarle el descuento.
titulo = "La Odisea"
precio = 12.50
stock = 4
es_socio = True # Luis es socio de Papyrus
DESCUENTO_SOCIO = 0.05
if stock > 0:
print(f"Vendiendo '{titulo}'...")
if es_socio:
precio_final = precio * (1 - DESCUENTO_SOCIO)
print(f"Descuento de socio aplicado: {precio_final:.2f} €")
else:
precio_final = precio
print(f"Precio sin descuento: {precio_final:.2f} €")
else:
print(f"No se puede vender '{titulo}': sin stock.")Salida:
Observa la indentación: el if es_socio: está indentado 4 espacios (dentro del primer if), y sus bloques internos están a 8 espacios. Cada nivel de anidamiento añade 4 espacios.
Consejo de estilo: dos niveles de anidamiento se leen bien; tres empiezan a costar; cuatro o más suelen indicar que el código necesita reorganizarse (a menudo con condiciones compuestas, que vemos a continuación, o con funciones, que verás en el módulo 3).
Condiciones compuestas con and, or y not
Ya conoces los operadores lógicos del módulo 1. Su gran momento es precisamente este: combinar varias comprobaciones en una sola condición.
| Operador | Resultado | Ejemplo | Evalúa a |
|---|---|---|---|
and |
True solo si ambas partes son True |
stock > 0 and es_socio |
True si hay stock y es socio |
or |
True si al menos una parte es True |
stock == 0 or precio > 50 |
True si está agotado o es caro |
not |
Invierte el valor | not es_socio |
True si no es socio |
Con and podemos reescribir el ejemplo anterior sin anidar, cuando solo nos interesa un caso concreto:
titulo = "La Odisea"
precio = 12.50
stock = 4
es_socio = True
DESCUENTO_SOCIO = 0.05
if stock > 0 and es_socio:
precio_final = precio * (1 - DESCUENTO_SOCIO)
print(f"Venta a socio: '{titulo}' por {precio_final:.2f} €")
elif stock > 0:
print(f"Venta normal: '{titulo}' por {precio:.2f} €")
else:
print(f"'{titulo}' está agotado.")Y con or, Ana puede detectar libros que requieren su atención por cualquiera de dos motivos:
Dos detalles importantes de los operadores lógicos en condiciones:
- Evaluación en cortocircuito: en
a and b, siaesFalse, Python ni siquiera evalúab(el resultado ya no puede serTrue). Ena or b, siaesTrue, no evalúab. Esto se aprovecha para escribir condiciones seguras, comoif stock > 0 and 10 / stock < 3:— la división nunca se ejecuta sistockes0. - Encadenado de comparaciones: Python permite escribir
if 1 <= stock <= 3:en lugar deif stock >= 1 and stock <= 3:. Ambas son equivalentes, pero la primera es más legible y muy idiomática.
Cuando una condición compuesta mezcla and y or, usa paréntesis para dejar clara la intención (recuerda que and tiene prioridad sobre or):
# ¿Aplica promoción? Socios, o compras caras de clásicos
if es_socio or (precio > 15 and es_clasico):
...Truthiness: valores que se comportan como True o False
Hasta ahora nuestras condiciones eran comparaciones explícitas (stock > 0). Pero Python permite poner cualquier valor como condición, y lo convertirá automáticamente a booleano. A esta conversión implícita se la llama truthiness (algo así como "veracidad").
La regla es sencilla de recordar: lo vacío y lo nulo es falso; el resto, verdadero. Estos son los valores falsy (que evalúan a False) más habituales:
| Valor | Tipo | ¿Por qué es falsy? |
|---|---|---|
False |
bool | Es el falso literal |
0, 0.0 |
int, float | El cero numérico |
"" |
str | Cadena vacía |
None |
NoneType | Ausencia de valor |
[], (), {} |
colecciones | Colecciones vacías (las verás en el módulo 4) |
Todo lo demás es truthy: 1, -3, 0.01, "hola", " " (¡una cadena con un espacio no está vacía!), etc.
Puedes comprobarlo en el REPL con bool():
¿Para qué sirve en la práctica? Para escribir condiciones más naturales. Estas dos versiones son equivalentes, y la segunda es la idiomática en Python:
stock = 4
# Versión explícita
if stock > 0:
print("Hay stock.")
# Versión idiomática usando truthiness
if stock:
print("Hay stock.")Y muy útil con input(), que como recordarás siempre devuelve str. Si el usuario pulsa Intro sin escribir nada, devuelve la cadena vacía "", que es falsy:
nombre = input("Nombre del cliente (Intro para omitir): ")
if not nombre:
nombre = "Cliente anónimo"
print(f"Bienvenido a Papyrus, {nombre}.")Aquí not nombre es True cuando nombre está vacío, así que asignamos un valor por defecto. Este patrón (comprobar si una entrada está vacía) es constante en programas reales.
Matiz: usa truthiness cuando la pregunta natural sea "¿hay algo aquí?" (¿hay texto?, ¿hay unidades?). Si la pregunta es sobre un valor concreto ("¿el stock es exactamente 0?", "¿la respuesta es 's'?"), la comparación explícita (==) comunica mejor la intención.
El operador ternario: condicionales en una línea
Cuando lo único que hace un if/else es elegir entre dos valores, Python ofrece una forma compacta llamada expresión condicional u operador ternario:
Compara la versión clásica con la ternaria para calcular el precio de Luis:
precio = 9.95 # Hamlet
es_socio = True
DESCUENTO_SOCIO = 0.05
# Versión clásica: 4 líneas
if es_socio:
precio_final = precio * (1 - DESCUENTO_SOCIO)
else:
precio_final = precio
# Versión ternaria: 1 línea, mismo resultado
precio_final = precio * (1 - DESCUENTO_SOCIO) if es_socio else precio
print(f"Precio final: {precio_final:.2f} €")También brilla dentro de f-strings, por ejemplo para el ticket de Papyrus:
Reglas de uso del ternario:
- Es una expresión: produce un valor, así que puedes asignarla, imprimirla o pasarla a una función. Un
ifnormal es una sentencia y no produce valor. - Se lee "A si condición, si no B", que es casi lenguaje natural.
- Úsalo solo para elecciones simples entre dos valores. Si necesitas ejecutar varias instrucciones, o anidar ternarios dentro de ternarios, vuelve al
if/elseclásico: la legibilidad manda.
Errores Comunes y Consejos
- Olvidar los dos puntos al final de
if,elifoelseproduceSyntaxError. Es el fallo número uno de todo principiante; revísalo antes que nada. - Confundir
=con==:if stock = 0:es un error de sintaxis.=asigna,==compara. Python te protege aquí negándose a ejecutarlo. - Indentación inconsistente: mezclar 4 espacios con tabuladores o con 3 espacios provoca
IndentationError. Configura tu editor (VS Code lo hace por defecto) para insertar 4 espacios al pulsar Tab. - Ordenar mal los
elif: como viste, si una condición amplia va antes que una específica, la específica nunca se ejecutará. Ordena de lo más concreto a lo más general. - Comparar floats con
==: por la imprecisión de los decimales que vimos en el módulo 1,0.1 + 0.2 == 0.3daFalse. Para dinero en condicionales, compara con un margen:abs(total - esperado) < 0.001. if es_socio == True:funciona, pero es redundante:es_socioya es un booleano. Escribeif es_socio:y, para el caso contrario,if not es_socio:.- Consejo: cuando una condición compuesta se vuelva difícil de leer, guárdala en una variable con nombre descriptivo:
puede_comprar = stock > 0 and es_socioy luegoif puede_comprar:. El código se autodocumenta.
Ejercicios
Ejercicio 1: clasificador de stock
Escribe un script nivel_stock.py que, dadas las variables titulo y stock, imprima:
"AGOTADO — pedir urgente"si el stock es 0."Stock bajo — reponer pronto"si está entre 1 y 3 (ambos incluidos)."Stock correcto"si está entre 4 y 10."Exceso de stock — no pedir más"si es mayor que 10.
Pruébalo con los tres libros del catálogo: La Odisea (4), Hamlet (6) y El Quijote (8).
Ejercicio 2: precio final de una venta
Amplía venta_socio.py: dadas las variables precio, es_socio y stock, el script debe:
- Si no hay stock, imprimir
"Venta imposible: sin stock"y nada más. - Si hay stock, calcular el precio con
IVA_LIBROS = 0.04incluido. - Aplicar además
DESCUENTO_SOCIO = 0.05sobre el precio base solo si el cliente es socio (el descuento se aplica antes del IVA). - Imprimir el precio final con dos decimales.
Comprueba que para El Quijote (15.90 €) comprado por Luis (socio) el resultado es 15.71 €.
Ejercicio 3: validador de alta de libro
En ficha_libro.py prometimos validar la entrada. Da el primer paso: pide con input() el título de un libro y su precio. Usando truthiness y un ternario:
- Si el título está vacío, imprime
"Error: el título es obligatorio". - Si no, convierte el precio a
floate imprime, en una sola f-string con ternario,"<título>: económico"si cuesta menos de 12 € o"<título>: premium"en caso contrario.
Soluciones
Solución 1:
titulo = "La Odisea"
stock = 4
if stock == 0:
mensaje = "AGOTADO — pedir urgente"
elif stock <= 3:
mensaje = "Stock bajo — reponer pronto"
elif stock <= 10:
mensaje = "Stock correcto"
else:
mensaje = "Exceso de stock — no pedir más"
print(f"{titulo}: {mensaje}")Fíjate en que no hace falta escribir 1 <= stock <= 3 en el segundo caso: si llegamos a ese elif, ya sabemos que stock no es 0, así que basta con stock <= 3. Cada rama puede apoyarse en que las anteriores fallaron. Los tres libros del catálogo caen en "Stock correcto".
Solución 2:
IVA_LIBROS = 0.04
DESCUENTO_SOCIO = 0.05
precio = 15.90 # El Quijote
es_socio = True # Luis
stock = 8
if stock == 0:
print("Venta imposible: sin stock")
else:
base = precio * (1 - DESCUENTO_SOCIO) if es_socio else precio
precio_final = base * (1 + IVA_LIBROS)
print(f"Precio final: {precio_final:.2f} €")Cálculo paso a paso: 15.90 × 0.95 = 15.105 (descuento de socio) y 15.105 × 1.04 = 15.7092, que la f-string redondea a 15.71 €. El ternario resuelve en una línea la elección del precio base.
Solución 3:
titulo = input("Título del libro: ")
if not titulo:
print("Error: el título es obligatorio")
else:
precio = float(input("Precio (€): "))
print(f"{titulo}: {'económico' if precio < 12 else 'premium'}")not titulo es True cuando el usuario pulsa Intro sin escribir (cadena vacía, falsy). El ternario va dentro de la f-string, entre llaves, porque es una expresión y produce un valor. Nota: si el usuario escribe un precio no numérico, float() fallará con ValueError; aprenderemos a manejarlo con elegancia en el módulo 7.
Conclusión
Tus programas ya saben decidir. Has aprendido la sentencia if con sus compañeras elif y else, a anidar decisiones cuando una depende de otra, a combinar comprobaciones con and/or/not (incluido el cortocircuito), a aprovechar el truthiness de los valores vacíos y a condensar elecciones simples con el operador ternario. Papyrus ya puede responder a sus dos preguntas de negocio esenciales: si hay stock y si toca aplicar el descuento de socio.
Pero seguimos decidiendo libro a libro, con variables sueltas. Ana tiene un catálogo entero, y comprobar el stock de cada título copiando y pegando ifs no escala. Lo que necesitamos es repetir una operación sobre muchos elementos, y de eso trata exactamente la siguiente lección: los bucles for y while, con los que recorreremos el catálogo completo de Papyrus y sumaremos la caja del día en unas pocas líneas.
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
- Entornos Virtuales y Gestión de Paquetes
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones con Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
- Buenas Prácticas y Registro de Errores con logging
Módulo 8: Temas Avanzados
- Anotaciones de Tipos (type hints)
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Pruebas con pytest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn
