Combinando expresiones lógicas en estructuras condicionales
Veamos cómo podemos combinar expresiones lógicas en estructuras condicionales en Python para mejorar nuestro código.
Supongamos que tenemos el siguiente problema: queremos comparar dos números enteros, x
e y
, para saber si son distintos o si son iguales.
Analicemos el diagrama de flujo de este problema:
Este diagrama de flujo es teórico para entender el funcionamiento, pero no es posible de ejecutar en ningún lenguaje de programación, puesto que no es posible mezclar los caminos de flujo verdadero como se muestra en el diagrama.
¿Cuál es la primera condición que se evalúa? Si x < y
. Si la respuesta es verdadera entonces seguimos la flecha de flujo por la rama verdadera hasta obtener el resultado "x es distinto de y" y luego continuamos hasta el final del programa.
¿Pero qué pasa si x
no es menor que y
? ¿Qué pasa si x
es mayor que y
?
Si la respuesta a la condición anterior es falsa, entonces seguimos la flecha de flujo por la rama falsa y nos encontramos con una nueva condición: si x > y
. Si la respuesta es verdadera entonces seguimos la flecha de flujo por la rama verdadera hasta obtener el mismo resultado de la condición anterior: "x es distinto de y" y luego continuamos hasta el final del programa, igual que en el caso anterior. Es decir, que podríamos reutilizar algunas de las mismas partes del diagrama para resolver nuestro problema. No necesitamos agregar flechas de flujo ni rombos de decisión ni rectángulos de procesos adicionales de manera innecesaria.
¿Qué pasa si x
tampoco es mayor que y
? ¿Qué pasa si x
es igual a y
?
Si la respuesta a la segunda condición también es falsa, entonces seguimos la flecha de flujo por la rama falsa y nos encontramos con el resultado "x es igual a y" y luego continuamos hasta el final del programa.
Cabe destacar que, en este caso, no necesitamos hacer una tercera pregunta, otro diamante, para saber si x
es igual a y
puesto que al no existir otra posible respuesta, siempre será verdadera. Podemos imprimir inmediatamente el resultado y luego detener el programa. En este caso, esta pregunta es redundante y no es necesaria. Identifica a la respuesta por descarte, la última opción posible.
Si analizamos lo que acabamos de describir, podemos observar que las dos preguntas, en caso de ser verdaderas, nos llevan al mismo resultado. Por lo tanto, podemos combinar estas dos preguntas en una sola pregunta que nos permita obtener el mismo resultado.
Al igual que como lo hacemos en español, en inglés o en cualquier otro idioma, en programación también podemos hacer varias preguntas al mismo tiempo combinando los resultados obtenidos de alguna manera lógica para obtener una respuesta más precisa.
¡Para recordar!
Al combinar expresiones lógicas en estructuras condicionales, podemos simplificar nuestro código y hacerlo más eficiente.
En lugar de hacer varias preguntas, podemos combinar estas preguntas en una sola pregunta que nos permita obtener el mismo resultado.
Esto nos permite escribir un código más limpio y más fácil de entender.
¿Cómo logramos hacer esto?
El operador lógico or
El operador lógico or
se utiliza para combinar dos o más condiciones y determinar si una expresión compuesta es verdadera o falsa, dependiendo de si al menos una de las condiciones es verdadera.
Por ejemplo, modifiquemos el código anterior para saber si x
es o no es igual a y
:
x = int(input("¿Cuál es el valor de x? "))
y = int(input("¿Cuál es el valor de y? ")
if x < y or x > y:
print("x es distinto de y")
else:
print("x es igual a y")
Si modificamos el diagrama de flujo, veríamos algo como esto:
Este diagrama de flujo si puede ser convertido en código utilizando un lenguaje de programación, puesto que aquí no se mezcla ningún camino de flujo de manera incorrecta.
Ahora, con este nuevo diseño, revisemos los escenarios posibles:
En este caso, hemos ingresado
1
parax
y2
paray
. Como1
es menor que2
, la condiciónx < y
es verdadera (y ya no nos importa lo que resuelvax > y
), por lo que se imprime "x es distinto de y".
Si ejecutamos el programa nuevamente, pero esta vez ingresamos 2
para x
y 1
para y
, obtendremos el siguiente resultado:
En este caso,
2
es mayor que1
, por lo que la condiciónx > y
es verdadera (y entonces descartamos el resultado falso que obtuvimos previamente conx < y
), por lo que se imprime "x es distinto de y".
Finalmente, si ingresamos el mismo valor para x
e y
, obtendremos el siguiente resultado:
En este caso,
1
es igual a1
, por lo que la condiciónx < y or x > y
resulta falta, producto de que ambas condiciones internas son falsas, por lo que se imprime "x es igual a y".
Si bien nuestro código es correcto, podemos mejorarlo aún más. ¿Cómo podríamos hacerlo? Aunque sea una pequeña mejoría. ¿Qué piensas?
Tómate un momento para pensar en cómo podríamos mejorar nuestro código y luego continúa en la siguiente sección para descubrir la respuesta.
El operador lógico and
El operador lógico and
se utiliza para combinar dos o más condiciones y determinar si una expresión compuesta es verdadera o falsa, dependiendo de si todas las condiciones son verdaderas. Es decir, una conjunción de una, dos o más preguntas que quizás queramos hacer a la vez.
Veamos un ejemplo de ello. Vamos a crear un nuevo programa, llamado "calificacion.py"
calificacion = int(input("Ingrese la calificacion del estudiante (1/100): "))
if calificacion >= 90 and calificacion <= 100:
print("Nivel A")
elif calificacion >= 80 and calificacion < 90: # No es <= 90 porque ya se evaluó el caso de 90
print("Nivel B")
elif calificacion >= 70 and calificacion < 80: # No es <= 80 porque ya se evaluó el caso de 80
print("Nivel C")
elif calificacion >= 60 and calificacion < 70: # No es <= 70 porque ya se evaluó el caso de 70
print("Nivel D")
else: # Caso por defecto
print("Nivel F")
En este código, le pedimos al usuario que ingrese una calificación para un estudiante, que debe ser un número entre 1 y 100. Luego, utilizamos una estructura condicional para determinar la calificación correspondiente al rango en el que se encuentra la calificación ingresada.
Recordemos que la función
input()
siempre devuelve una cadena de texto, por lo que debemos convertir el valor ingresado a un número entero utilizando la funciónint()
para poder compararlo con otros números enteros.
Si ejecutamos el programa y probamos con diferentes calificaciones, obtendremos los siguientes resultados:
Ingrese la calificacion del estudiante (1/100): 100
Nivel A
Ingrese la calificacion del estudiante (1/100): 95
Nivel A
Ingrese la calificacion del estudiante (1/100): 89
Nivel B
Ingrese la calificacion del estudiante (1/100): 71
Nivel C
Ingrese la calificacion del estudiante (1/100): 39
Nivel F
En este caso, si la calificación ingresada es mayor o igual a 90 y menor o igual a 100, se imprime "Nivel A". Si la calificación está entre 80 y 89, se imprime "Nivel B". Si la calificación está entre 70 y 79, se imprime "Nivel C". Si la calificación está entre 60 y 69, se imprime "Nivel D". Y si la calificación es menor a 60, se imprime "Nivel F", el caso por defecto.
Encadenando operadores de comparación
Tenemos nuestro programa de calificaciones. Funciona bien, pero estaría mejor si lográsemos robustecer la lógica un poco más. No está mal. Es correcta. Pero, ¿Podemos reducir la probabilidad de errores, ahora o más adelante? ¿Podemos aumentar la legibilidad del código? ¿Podemos aumentar la eficiencia de ejecución? ¿Podemos conseguir que la computadora realice menos pasos y seguir obteniendo el mismo resultado?
En Python, podemos encadenar operadores de comparación para simplificar nuestras expresiones condicionales. Por ejemplo, en lugar de escribir calificacion >= 90 and calificacion <= 100
, podemos escribir 90 <= calificacion <= 100
. ¿Cómo? ¿De dónde sale esto? ¿Cómo funciona? ¿Es posible? ¡Sí! ¡Es posible! ¡Y es más simple! ¡Y es más eficiente! ¡Y es más legible! ¡Y es más elegante! ¡Y es más Python!
Analicemos como es el proceso de transformación:
-
Partimos de nuestro código original:
calificacion.pycalificacion = int(input("Ingrese la calificacion del estudiante (1/100): ")) if calificacion >= 90 and calificacion <= 100: print("Nivel A") elif calificacion >= 80 and calificacion < 90: # No es <= 90 porque ya se evaluó el caso de 90 print("Nivel B") elif calificacion >= 70 and calificacion < 80: # No es <= 80 porque ya se evaluó el caso de 80 print("Nivel C") elif calificacion >= 60 and calificacion < 70: # No es <= 70 porque ya se evaluó el caso de 70 print("Nivel D") else: # Caso por defecto print("Nivel F")
-
Vamor a invertir la lógica de la primera de las condiciones en cada
if
:calificacion.pycalificacion = int(input("Ingrese la calificacion del estudiante (1/100): ")) if 90 <= calificacion and calificacion <= 100: # Refactorizamos la primera condición print("Nivel A") elif 80 <= calificacion and calificacion < 90: # Refactorizamos la primera condición print("Nivel B") elif 70 <= calificacion and calificacion < 80: # Refactorizamos la primera condición print("Nivel C") elif 60 <= calificacion and calificacion < 70: # Refactorizamos la primera condición print("Nivel D") else: # Caso por defecto print("Nivel F")
En este caso, hemos invertido la lógica de la primera condición en cada
if
para que la comparación sea90 <= calificacion
en lugar decalificacion >= 90
. Esto nos permite encadenar los operadores de comparación de manera más eficiente y legible. Por ejemplo, en lugar de decir que "calificacion es mayor o igual que 90", decimos que "90 es menor o igual que calificación".¡Para recordar!
Esta inversión no es posible realizarse en todos los lenguajes de programación. De hecho, es inviable en la mayoría de ellos. Python es un lenguaje que permite esta flexibilidad y legibilidad en la escritura de código.
-
Luego, simplificamos la expresión de comparación combinando las expresiones lógicas en cada caso. Esto tampoco es posible en todos los lenguajes de programación. Pero en Python, sí lo es. Y es una de las características que lo hacen tan atractivo para muchos programadores.
calificacion.pycalificacion = int(input("Ingrese la calificacion del estudiante (1/100): ")) if 90 <= calificacion <= 100: # Refactorizamos la primera condición print("Nivel A") elif 80 <= calificacion < 90: # Refactorizamos la primera condición print("Nivel B") elif 70 <= calificacion < 80: # Refactorizamos la primera condición print("Nivel C") elif 60 <= calificacion < 70: # Refactorizamos la primera condición print("Nivel D") else: # Caso por defecto print("Nivel F")
En este caso, hemos simplificado la expresión de comparación en cada
if
utilizando la forma90 <= calificacion <= 100
en lugar de90 <= calificacion and calificacion <= 100
. Esto nos permite escribir un código más limpio y más fácil de entender.
¡Para recordar!
Al combinar expresiones lógicas en estructuras condicionales, podemos simplificar nuestro código y hacerlo más eficiente.
En lugar de hacer varias preguntas, podemos combinar estas preguntas en una sola pregunta que nos permita obtener el mismo resultado.
Esto nos permite escribir un código más limpio y más fácil de entender.
¿Qué más podemos hacer para mejorar nuestro código?
Reflexionando sobre la optimización de expresiones condicionales
Cada vez que el programa deba evaluar un nivel de calificación, es probable que no sea necesario realizar dos preguntas para poder tomar la decisión correcta. Pensemos lo siguiente:
Es necesario preguntarse ¿Es mayor o igual a 90 y menor que 100? ¿Es mayor que 80 y menor que 90? Y así sucesivamente...
Si repasamos la lógica, nos daremos cuenta de que, en nuestra primera condición compuesta, si la calificación es mayor o igual a 90 y menor o igual a 100, el estudiante obtiene una A. Pero también nos daremos cuenta de que si no es así, pero si, en la segunda condición, la calificación es mayor o igual a 80, el estudiante obtiene una B.
¿Por qué no evaluamos si la calificación es menor a 90 también?
Pues porque si llegamos a evaluar esta seguna condición es porque la primera condición, que evalúa una calificación de 90 o más, resultó falsa. Por lo tanto, si la calificación es mayor o igual a 80, pero no es mayor o igual a 90, entonces sabemos que está en el rango de 80 a 89, menor a 90.
Con este concepto, reformularíamos nuestra lógica de las expresiones condicionales de la siguiente manera:
calificacion = int(input("Ingrese la calificacion del estudiante (1/100): "))
if 90 <= calificacion <= 100:
print("Nivel A")
elif calificacion >= 80: # Refactorizamos la condición completa
print("Nivel B")
elif calificacion >= 70: # Refactorizamos la condición completa
print("Nivel C")
elif calificacion >= 60: # Refactorizamos la condición completa
print("Nivel D")
else: # Caso por defecto
print("Nivel F")
En lugar de hacer dos preguntas cada vez, verificando los límites inferiores y superiores de cada rango de valores, estamos siendo un poco más inteligentes al preguntar si la calificación es mayor o igual que 90 y menor o igual que 100, obteniento "Nivel A"
Por el contrario, si la calificación es mayor que 80, obtiene "Nivel B". Pero, ¿Por qué no puede ser "Nivel A"? Porque debido a la lógica
if… elif
, ya hemos verificado previamente si el puntaje del estudiante es mayor que 90, siendo falsa la respuesta. Entonces, implícitamente sabes que está en algún lugar en el rango de 80 a 89; de lo contrario, sabes que está en el rango de 70 a 79, o está en el rango siguiente hacia abajo, sucesivamente.
Esta es una optimización menor que nos permite hacer menos preguntas. Pero nuevamente, podemos decir que esto nos permite simplificar la lógica de las expresiones condicionales y hacer que el código sea un poco más legible, ciertamente más conciso y, con suerte, más mantenible a largo plazo.