Ilustración conceptual de una puerta clasificada por tres rutas de decisión con resultados separados.

Condicionales: decidir qué debe hacer un programa

Una decisión, dos caminos. Me han reservado un artículo entero para enseñarle a un ordenador algo que ya haces al decidir si necesitas paraguas. Aceptaré este desafío desmesurado con una condición: al terminar sabrás qué instrucciones se ejecutan y cuáles se saltan, sin tener que confiar en que las llaves o la indentación decoren el resultado.

Para el recorrido básico basta con conocer variables y comparaciones. Empezaremos con dos comprobaciones pequeñas sobre datos inventados de una puerta y después veremos una cadena de alternativas que esconde una rama. La clasificación completa y su versión C# quedan como ampliaciones: utilizan funciones y otros conceptos que puedes estudiar después. Ninguno de los ejemplos modifica un modelo.

Tabla de contenidos

Primer paso: comprobar dos condiciones independientes

Imagina una puerta de ejemplo con una altura y un código. Queremos mostrar dos avisos si se cumplen dos condiciones: que la altura sea inferior al límite del ejercicio y que el código esté vacío. Un if pregunta si su comparación es verdadera; cuando lo es, ejecuta las líneas indentadas que tiene debajo. Guarda este fragmento en un archivo Python independiente y ejecútalo: no necesita funciones ni recorridos.

				
					altura_m = 1.8
codigo = ""
limite_del_ejercicio_m = 2.0

if altura_m < limite_del_ejercicio_m:
    print("altura inferior al limite del ejercicio")
if codigo == "":
    print("codigo vacio")
				
			

Aparecen los dos mensajes: la altura es menor que 2.0 y el código está vacío. Cada if se comprueba por separado. La altura ya es numérica y el código ya es texto; el límite es inventado, no una exigencia normativa. Cambia la altura a 2.1: solo aparecerá el aviso de código. Después escribe D01 en el código: no aparecerá ninguno. Esas variaciones permiten seguir el programa línea a línea, una actividad modesta que evita atribuirle poderes adivinatorios.

Cuando quieres elegir una sola respuesta, utiliza una cadena if, elif, else: se ejecuta la primera rama cuya condición sea verdadera; si ninguna lo es, se utiliza else. Para probarlo, cambia el segundo if del fragmento por elif y recupera la altura 1.8. El aviso de código dejará de aparecer porque la primera rama ya ha sido elegida. La sintaxis funciona; lo que ha cambiado es la pregunta que contesta el programa.

Ya puedes distinguir controles independientes de alternativas excluyentes. Si necesitas ambos avisos, conserva los dos if. Si necesitas un único diagnóstico, diseña las ramas en orden. El siguiente ejemplo muestra por qué una condición demasiado amplia se queda con casos que otra necesitaba recibir. Tener una rama escrita y no darle ninguna oportunidad es una forma de burocracia que también hemos conseguido automatizar.

La primera coincidencia puede esconder todas las demás

Una variable puede contener un texto vacío sin ser nula. Si preguntamos únicamente si existe un valor distinto de None, esa cadena superará la comprobación. El siguiente fragmento Python reproduce el fallo de la apertura. Guárdalo como ejercicio independiente para observar lo que hace, sin incorporarlo a la regla que utilizaremos después.

				
					codigo = ""

if codigo is not None:
    print("cumple")
elif codigo == "":
    print("incumple: codigo vacio")
else:
    print("no evaluable")
				
			

Imprime cumple. La primera condición es verdadera, así que se ejecuta su bloque y se descartan las alternativas de esa cadena. elif significa que se comprueba otra condición cuando las anteriores no han elegido una rama. La segunda pregunta no funciona como un control adicional obligatorio sobre todo lo que pasó por la primera. El programa ha encontrado una respuesta antes de llegar a ella.

Cambiar el orden para comprobar el vacío antes del nulo arreglaría esa entrada concreta, pero todavía no demostraría que un código cumple. "X99" también es distinto de nulo y no está vacío; aun así, puede quedar fuera del catálogo admitido. La condición «tiene algún contenido» y la condición «ese contenido está permitido» describen propiedades diferentes. Yo no llamaría «cumple» a una rama hasta haber preguntado lo necesario para sostener ese resultado.

La guía de control de flujo de Python presenta la cadena if, elif y else. El mecanismo es pequeño. Diseñar las alternativas requiere algo más que recordar las palabras: las primeras preguntas pueden proteger operaciones posteriores o absorber casos que otra rama necesitaba distinguir. Una rama escrita no equivale a una rama alcanzable.

Ampliación: acordar los resultados de una regla

Nuestro catálogo ficticio admite D01 y D02. Si el código es uno de esos textos, el resultado será «cumple». Si recibimos una cadena vacía, formada solo por espacios o ajena al catálogo, devolveremos «incumple», conservando el motivo. Si el valor es nulo o llega con otro tipo, la respuesta será «no evaluable». Es una política del ejercicio, no una definición universal de calidad BIM.

Los espacios merecen una decisión explícita. Trataremos una cadena de espacios como código vacío, pero no quitaremos espacios a un código antes de compararlo con el catálogo. Por tanto, " D01 " seguirá fuera del catálogo. Alguien podría aprobar una normalización que eliminase esos márgenes; aquí no lo hemos acordado. Limpiar antes de comparar sin anunciarlo consigue una herramienta tolerante y un criterio que ya no se parece al que recibió el lector.

También mantendremos separados «incumple» y «no evaluable». El primero indica que hemos podido aplicar la regla y el dato no la satisface. El segundo explica que falta una condición para realizar esa evaluación. Un parámetro ausente en Revit necesitaría además información sobre la lectura del elemento; nuestra función solo recibe un valor ya obtenido. No puede deducir si un nulo procede de un parámetro existente, de una extracción incompleta o de una decisión del origen.

Esa frontera permite repartir el trabajo. La parte que consulta el modelo debe explicar qué ha podido leer. La regla que veremos decide sobre el valor recibido. El informe relaciona después esa respuesta con el identificador. Concentrar todo en una función que consulta, interpreta, rellena y escribe puede parecer cómodo al principio. Cuando aparezca el primer «cumple» inexplicable, tendrás que investigar las cuatro cosas a la vez. Reservaría mi entusiasmo para una distribución algo menos hospitalaria con los errores.

Ampliación: reunir las decisiones en una función

Esta segunda lectura utiliza funciones, tipos y retornos. Puedes saltarla hasta haber trabajado esos conceptos: el recorrido básico anterior ya permite decidir entre if independientes y una cadena de alternativas. Ahora reunimos el orden de decisiones en evaluar_codigo, que recibe un código y devuelve estado y motivo. Las seis llamadas finales muestran los casos sin añadir todavía un bucle.

				
					def evaluar_codigo(codigo):
    if codigo is None:
        return "no evaluable", "valor nulo"
    elif not isinstance(codigo, str):
        return "no evaluable", "tipo inesperado"
    elif codigo.strip() == "":
        return "incumple", "codigo vacio"
    elif codigo in ("D01", "D02"):
        return "cumple", "en catalogo"
    else:
        return "incumple", "fuera del catalogo"

print("P01", evaluar_codigo("D01"))
print("P02", evaluar_codigo(""))
print("P03", evaluar_codigo(None))
print("P04", evaluar_codigo("X99"))
print("P05", evaluar_codigo(42))
print("P06", evaluar_codigo("D02"))
				
			

P01 y P06 cumplen. P02 incumple por código vacío; P04 incumple por valor fuera del catálogo. P03 no se puede evaluar por nulo y P05 por tipo inesperado. No convertimos el número 42 en texto para seguir buscando una respuesta aceptable: el tipo forma parte de lo que esta función espera recibir. La salida conserva una diferencia que podrá ayudar a localizar el fallo de origen.

La primera rama detiene el recorrido del nulo. La segunda protege las operaciones de texto frente a otros tipos. Solo después utilizamos strip, que obtiene una versión sin espacios exteriores para comprobar si queda algún carácter. La comparación con el catálogo se hace sobre codigo, el original. Cada return devuelve el resultado y termina esa llamada, de modo que una entrada clasificada no continúa hacia otra respuesta.

Podríamos escribir esos primeros controles como varios if separados y conservar los retornos inmediatos. También darían una única salida por llamada, porque return termina la función. En este ejemplo he mantenido una cadena de alternativas para hacer visible el recorrido excluyente. La decisión importante es comprender dónde termina la ejecución; sustituir palabras hasta que el resultado coincida no enseña a distinguir una ruta de varias comprobaciones independientes.

El bloque else recoge lo que queda después de las condiciones anteriores. En este caso ya sabemos que estamos ante un texto con contenido que no pertenece al catálogo. No significa «todos los errores posibles del sistema» ni protege automáticamente una lectura de archivos o una llamada a una API. Su significado depende de las preguntas que lo preceden. Si mañana añadimos una nueva forma de entrada, habrá que revisar si sigue siendo honesto etiquetar todo lo restante como valor fuera del catálogo.

Variante C#: la misma clasificación por ramas

En C# podemos expresar la misma política con if, else if y else. Los bloques utilizan llaves en lugar de la indentación significativa de Python. El programa siguiente sirve como Program.cs de un proyecto de consola dirigido a .NET 8. La entrada object? permite presentar valores de tipos diferentes o nulos; cada rama acota qué podemos hacer con ellos antes de avanzar.

				
					using System;

static (string Estado, string Motivo) EvaluarCodigo(object? codigo)
{
    if (codigo is null)
        return ("no evaluable", "valor nulo");
    else if (codigo is not string texto)
        return ("no evaluable", "tipo inesperado");
    else if (texto.Trim() == "")
        return ("incumple", "codigo vacio");
    else if (texto == "D01" || texto == "D02")
        return ("cumple", "en catalogo");
    else
        return ("incumple", "fuera del catalogo");
}

Console.WriteLine($"P01 {EvaluarCodigo("D01")}");
Console.WriteLine($"P02 {EvaluarCodigo("")}");
Console.WriteLine($"P03 {EvaluarCodigo(null)}");
Console.WriteLine($"P04 {EvaluarCodigo("X99")}");
Console.WriteLine($"P05 {EvaluarCodigo(42)}");
Console.WriteLine($"P06 {EvaluarCodigo("D02")}");
				
			

El patrón codigo is not string texto comprueba si el valor no es una cadena. Cuando sí lo es, las ramas posteriores pueden trabajar con texto. Los pares devueltos llevan los nombres Estado y Motivo; al imprimirlos veremos la clasificación junto al identificador. La referencia de selección de C# describe estas instrucciones. Las seis decisiones esperadas coinciden con las de Python, aunque no estamos afirmando que todos los tipos y métodos de ambos lenguajes sean equivalentes.

La legibilidad depende también de conservar nombres y resultados consistentes. Si una versión devuelve «error» donde la otra devuelve «no evaluable», comparar sus salidas obligará a interpretar la intención del autor antes de comprobar la regla. Elegir los estados una vez y mantenerlos permite centrar la revisión en las decisiones. La variedad literaria me parece estupenda; introducirla en un catálogo de estados suele producir menos admiración.

Artículos relacionados

Respuestas

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *