Condicionales: tomar decisiones

"En el momento de la verdad solo hay dos clases de programadores: los que duermen tranquilos y los que prueban con datos." — folclore de la industria.

Qué vas a aprender en este capítulo

Hasta ahora tus programas hacen lo mismo siempre: la línea 1, después la 2, después la 3. En este capítulo aprendés a que el programa decida qué hacer según una condición — el primer ladrillo de la "inteligencia" que pone una computadora a trabajar de verdad. Vas a entender por qué Python usa indentación en vez de llaves, vas a evitar la trampa clásica = vs ==, y al final vas a hacer que la pupusería ofrezca distintos descuentos según la cantidad.

5.1 La idea: ramas en el camino

💡 Intuición

Imaginate manejando hacia UNIMO. Llegás a un semáforo. Si está en verde, seguís. Si está en rojo, frenás. Esa decisión — si pasa una cosa, hacé esto, si no, hacé aquello — es lo que en programación llamamos condicional.

Otro ejemplo: estás en la pupusería de la esquina. Si tu pedido es de 20 o más pupusas, te dan descuento. Si no, pagás precio lleno. Una condición, dos caminos.

Un condicional es la primera ruptura del orden lineal del programa. Hasta acá, las líneas se ejecutaban una tras otra. Con if, algunas líneas se saltan según una condición.

En el mundo real las decisiones se ramifican: vas al campus → ¿hay clase? → si hay → ¿está mi profesor? → ... Cada if puede tener otros if adentro. Esa estructura ramificada es la columna vertebral de cualquier programa real.

📜 Historia

El primer lenguaje "de alto nivel" con condicionales fue FORTRAN (1957). Su IF era distinto del actual: comparaba un valor con cero y saltaba a una de tres etiquetas según fuera negativo, cero o positivo:

IF (X-Y) 100, 200, 300

Confuso, pero práctico para el hardware de la época. ALGOL 60 introdujo el if-then-else legible que conocemos hoy. La elegancia ganó: todos los lenguajes modernos heredan esa estructura.

Python le agregó una vuelta interesante: en lugar de { } o begin/end para marcar el bloque, usa la indentación. Eso fue diseñado a propósito para forzar a los programadores a sangrar el código de la misma forma que los humanos lo leemos. Causa peleas religiosas entre fans de los espacios y los que prefieren llaves; pero el resultado en Python es un código uniforme entre todos los que lo usan, al menos en lo de la indentación.

5.2 La forma básica: if

📐 Fundamento

if condicion:
    # bloque que se ejecuta si la condición es verdadera
    instruccion_1
    instruccion_2
# acá ya estamos fuera del if

Anatomía:

  • La palabra if (siempre minúsculas).
  • Una condición — cualquier expresión que dé True o False.
  • Dos puntos : al final de la línea.
  • Un bloque indentado abajo.

Ejemplo:

edad = int(input("Edad: "))

if edad >= 18:
    print("Sos mayor de edad.")
    print("Podés votar.")

print("Gracias por usar el sistema.")

Si el usuario pone 25, imprime las tres líneas. Si pone 15, imprime solo la última — las indentadas se saltan.

La indentación es sintaxis, no decoración. En Python, los espacios al inicio de cada línea definen el bloque. La regla:

  • Todo lo que está más indentado que el if pertenece al bloque del if.
  • La primera línea que vuelve al nivel del if (o menos) está fuera.

Mezclar tabs y espacios da error (TabError). Convención del proyecto y del PEP 8: siempre 4 espacios, nunca tabs. Tu editor (VS Code, etc.) lo configura por vos.

⚠️ Trampa común

if x = 5. Mal: = asigna, == compara. Python te avisa con un SyntaxError. Lo correcto:

if x == 5:
    ...

En C y otros lenguajes esa confusión es más peligrosa porque no produce error de sintaxis (en C, if (x = 5) es legal y casi siempre incorrecto). Python te protege.

Olvidar los dos puntos.

if edad >= 18
    print("Mayor")

Falta el : al final del if. Python protesta:

SyntaxError: expected ':'

Indentación inconsistente.

if edad >= 18:
    print("Mayor")
   print("Adulto")     # un espacio menos: ¡error!
IndentationError: unindent does not match any outer indentation level

Acostumbrate a ver el indicador del editor (la barra vertical o las guías). Si las líneas no quedan alineadas, Python no las acepta.

5.3 else: el otro camino

if condicion:
    # camino A
    ...
else:
    # camino B
    ...

Exactamente uno de los dos bloques se ejecuta — nunca los dos, nunca ninguno.

edad = int(input("Edad: "))

if edad >= 18:
    print("Mayor de edad.")
else:
    print(f"Te faltan {18 - edad} años.")

5.4 elif: cadena de decisiones

Cuando hay más de dos opciones, se usa elif (abreviatura de "else if"):

nota = float(input("Nota (0-10): "))

if nota >= 9:
    letra = "A"
elif nota >= 8:
    letra = "B"
elif nota >= 7:
    letra = "C"
elif nota >= 6:
    letra = "D"
else:
    letra = "F"

print(f"Tu nota: {letra}")

Cómo funciona la cadena. Python evalúa las condiciones de arriba hacia abajo. La primera que sea True ejecuta su bloque y se sale de toda la cadena. Si ninguna se cumple, ejecuta el else. Por eso el orden importa:

# MAL: la primera condición atrapa todo
if nota >= 6:
    letra = "D"
elif nota >= 7:    # ¡nunca se evalúa, porque >= 6 ya capturó!
    letra = "C"

Regla: en una cadena if/elif, escribí las condiciones de la más restrictiva a la más laxa (o de mayor valor a menor, según el caso).

5.5 Condiciones compuestas

📐 Fundamento

Combiná comparaciones con and, or, not:

# AND: ambas condiciones tienen que cumplirse
if edad >= 18 and ciclo == 1:
    print("Estudiante de primer ciclo, mayor de edad")

# OR: al menos una se cumple
if dia == "sabado" or dia == "domingo":
    print("Fin de semana")

# NOT: invertir
if not está_lloviendo:
    print("Salgo a correr")

Comparaciones encadenadas (lujo de Python):

if 0 <= nota <= 10:
    print("Nota válida")

Es lo mismo que 0 <= nota and nota <= 10, pero más cercano a la matemática.

Operador in — pertenencia:

dia = input("Día: ").lower()
if dia in ("sabado", "domingo"):
    print("Fin de semana")

in con una colección revisa si el valor está adentro. Lo vamos a usar con listas, diccionarios, cadenas, etc.

Combinaciones útiles con paréntesis:

# Aprueba si nota >= 7 Y asistencia >= 75%, O si proyecto es excelente
if (nota >= 7 and asistencia >= 0.75) or proyecto >= 9:
    print("Aprobado")

Sin paréntesis, and tiene mayor precedencia que or. La expresión se interpreta como (nota>=7 and asistencia>=0.75) or proyecto>=9. Aún así, poné paréntesis — la claridad vale más que la economía de caracteres.

5.6 Anidación

Un if puede contener otros if:

nota = float(input("Nota: "))
asistencia = float(input("Asistencia (0-1): "))

if nota >= 6:
    if asistencia >= 0.75:
        print("Aprobado")
    else:
        print("Reprobado por inasistencia")
else:
    print("Reprobado por nota")

Eso a veces se puede aplanar con condiciones compuestas:

if nota >= 6 and asistencia >= 0.75:
    print("Aprobado")
elif nota >= 6:
    print("Reprobado por inasistencia")
else:
    print("Reprobado por nota")

Cuándo anidar y cuándo aplanar. Si los mensajes son distintos para cada caso, anidar es claro. Si hay un único mensaje "aprobado" y muchas razones de "no aprobado", aplanar con and es más limpio.

Demasiada anidación es un olor a código. Si estás en la cuarta sangría seguida de ifs, parate y pensá si podés:

  1. Combinar condiciones en una sola con and/or.
  2. Usar early return dentro de funciones (lo vemos en cap. 7).
  3. Reorganizar el flujo.

5.7 Operador ternario

Para asignar un valor según una condición, en una sola línea:

descuento = 0.05 if cantidad >= 20 else 0.0

Se lee: "descuento vale 0.05 si cantidad >= 20, sino 0.0".

Equivale a:

if cantidad >= 20:
    descuento = 0.05
else:
    descuento = 0.0

Cuándo usarlo. Asignaciones simples y claras. No abuses: si el ternario tiene 80 caracteres y tres operadores, escribí if/else normal. La economía no compensa la ilegibilidad.

5.8 Los datos como booleanos

Recordá del capítulo anterior: en Python, muchos valores se interpretan como True o False automáticamente.

Valor Como booleano
0, 0.0, "", [], {}, (), None False
Cualquier otra cosa True

Eso te permite escribir:

nombre = input("Nombre: ")
if nombre:
    print(f"Hola, {nombre}")
else:
    print("Tenés que escribir tu nombre")

if nombre: es lo mismo que if nombre != "":. Es legible y muy "pythónico".

Ojo: if x == None se considera mal estilo. Usá if x is None (compara identidad, no valor). El motivo es sutil; por ahora, simplemente memorizalo.

5.9 match (Python 3.10+)

Cuando hay muchas comparaciones contra valores fijos, match queda más legible:

dia = input("Día: ").lower()

match dia:
    case "lunes" | "martes" | "miercoles" | "jueves" | "viernes":
        print("Día laboral")
    case "sabado" | "domingo":
        print("Fin de semana")
    case _:
        print("Día inválido")

case _: es el caso por defecto (equivalente al else).

match es mucho más poderoso que un switch clásico — soporta patrones estructurales (descomponer tuplas, listas, objetos). Para este libro nos basta este uso, pero conviene saber que existe. Lo retomamos cuando veamos tipos compuestos.

5.10 Proyecto: descuento por cantidad en la pupusería

🏗️ Avance del proyecto — Pupusería La Esquina

La pupusería ofrece una escala de descuentos:

  • Menos de 10 pupusas: precio normal.
  • 10 a 19: 5% de descuento.
  • 20 a 49: 10%.
  • 50 o más (mayoreo): 15%.
# Pupuseria La Esquina - Capitulo 5: descuentos por cantidad

precio_unitario = 0.50   # asumimos solo de queso para simplificar
IVA = 0.13

cantidad = int(input("Cuántas pupusas? "))

# Decidir el porcentaje de descuento
if cantidad >= 50:
    porcentaje = 0.15
    categoria = "Mayoreo"
elif cantidad >= 20:
    porcentaje = 0.10
    categoria = "Por docena"
elif cantidad >= 10:
    porcentaje = 0.05
    categoria = "Familiar"
else:
    porcentaje = 0.0
    categoria = "Normal"

# Cálculos
subtotal = cantidad * precio_unitario
descuento = subtotal * porcentaje
base = subtotal - descuento
impuesto = base * IVA
total = base + impuesto

# Recibo
print()
print("=== Recibo Pupuseria La Esquina ===")
print(f"Cantidad:          {cantidad}")
print(f"Categoria:         {categoria}")
print(f"Subtotal:          ${subtotal:.2f}")
print(f"Descuento ({porcentaje:.0%}): -${descuento:.2f}")
print(f"Base imponible:    ${base:.2f}")
print(f"IVA (13%):         ${impuesto:.2f}")
print(f"TOTAL:             ${total:.2f}")

Validación rudimentaria. Si el usuario pone un número negativo, las cuentas dan negativo y el "recibo" es absurdo. Idealmente queremos rechazar entradas inválidas:

if cantidad <= 0:
    print("Cantidad inválida.")
else:
    # ... el cálculo

Lo dejamos así por ahora. En el próximo capítulo, con bucles, vamos a poder pedir el dato hasta que sea válido.

5.11 Resumen visual

Forma Cuándo usarla
if cond: Una sola decisión binaria.
if/else Dos caminos mutuamente excluyentes.
if/elif/.../else Tres o más caminos en cadena.
match/case Comparar contra varios valores fijos (Python 3.10+).
valor_si if cond else valor_no Asignación corta condicional.
if x: Cuando "no vacío / no cero" es la condición.
Reglas oro
Indentá con 4 espacios, nunca tabs.
Después del if/elif/else siempre va :.
== para comparar, = para asignar.
Poné paréntesis cuando combines and y or.

5.12 Ejercicios

✏️ Ejercicio 5.1 — Par o impar

Pedile al usuario un entero y mostrale si es par o impar.

✏️ Ejercicio 5.2 — Mayor de tres

Pedile tres notas y mostrá la mayor.

✏️ Ejercicio 5.3 — Año bisiesto

Un año es bisiesto si es divisible por 4, excepto si también es divisible por 100, a menos que también sea divisible por 400. Por ejemplo: 2000 es bisiesto, 1900 no, 2024 sí, 2023 no.

Pedile un año y decí si es bisiesto.

✏️ Ejercicio 5.4 — Triángulo válido

Tres números pueden ser los lados de un triángulo si cada lado es menor que la suma de los otros dos. Pedile al usuario tres lados y decí:

  • Si forman un triángulo o no.
  • Si lo forman: si es equilátero (3 iguales), isósceles (2 iguales) o escaleno (todos distintos).

✏️ Ejercicio 5.5 — Calculadora simple

Pedile dos números y una operación (+, -, *, /). Mostrá el resultado. Si la operación no es válida o se intenta dividir por cero, mostrá un mensaje claro.

5.13 Para profundizar


Definiciones nuevas: condicional, bloque, indentación, sentencia compuesta, condición, operador ternario, match/case.