Saltar al contenido
🐍 Curso de Python
/

Módulo 1 · Lección 12 de 59

Operadores lógicos

Combinar varias condiciones con and, or y not, la prioridad entre ellos y por qué la evaluación de cortocircuito te salva de errores.

⏱ 12 min de lectura

Una condición sola rara vez basta. Para entrar en el descuento hay que ser socio y haber gastado más de 50 euros. El formulario es inválido si falta el nombre o falta el correo. Y a veces lo que quieres es justo lo contrario de lo que sabes comprobar.

Python tiene tres operadores para eso, y en lugar de los símbolos raros de otros lenguajes usa tres palabras en inglés que se leen casi como una frase.

and: las dos cosas#

and da True solo cuando ambos lados son verdaderos:

IzquierdaDerechaand
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse
python
edad = 25
tiene_carnet = True

print(edad >= 18 and tiene_carnet)
Salida en pantalla
True

or: al menos una#

or da True cuando alguno de los dos lados es verdadero:

IzquierdaDerechaor
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse
python
dia = "sábado"
festivo = False

print(dia == "sábado" or dia == "domingo" or festivo)
Salida en pantalla
True

Se pueden encadenar tantos or como quieras, como en ese ejemplo con tres. Lo mismo vale para and.

not: lo contrario#

not es el único que trabaja con un solo valor: le da la vuelta.

Valornot
TrueFalse
FalseTrue
python
nota = 4.5

print(not nota >= 5)
Salida en pantalla
True

Ese ejemplo, sin embargo, es justo el mal uso de not. not nota >= 5 es una forma retorcida de escribir nota < 5. Reserva not para cuando no exista un operador directo:

python
respuesta = "  "

print(not respuesta.strip())
Salida en pantalla
True

Ahí sí se lee bien: "si no hay respuesta".

Prioridad#

Cuando mezclas operadores en la misma expresión, Python aplica este orden:

PrioridadOperadores
1 (primero)Los aritméticos: **, *, /, //, %, +, -
2Las comparaciones: ==, !=, <, >, <=, >=
3not
4and
5 (último)or

De ahí salen dos consecuencias prácticas. La primera es que las comparaciones se calculan antes que los operadores lógicos, así que no necesitas paréntesis alrededor de cada una:

python
if edad >= 18 and nota >= 5:       # correcto y legible
if (edad >= 18) and (nota >= 5):   # significa lo mismo, con ruido de más

La segunda es que and se calcula antes que or, lo cual sí puede cambiar el resultado:

python
print(True or False and False)
print((True or False) and False)
Salida en pantalla
True
False

En la primera línea Python calcula primero False and False, que es False, y luego True or False, que es True. En la segunda los paréntesis fuerzan el orden contrario. Es exactamente el mismo fenómeno que 2 + 3 * 4: and es la multiplicación y or es la suma de la lógica.

python
edad = 30
socio = False

print(edad < 18 or edad > 65 and socio)
print((edad < 18 or edad > 65) and socio)
Salida en pantalla
False
False

Aquí las dos dan lo mismo por casualidad, con estos datos concretos. Cambia socio a True y edad a 70 y verás que la primera da True y la segunda también; prueba con edad = 10 y socio = False y se separan. Ese "depende de los datos" es precisamente el problema:

Evaluación de cortocircuito#

Python es perezoso con and y or: deja de evaluar en cuanto sabe el resultado.

  • En a and b, si a es falso el resultado ya es falso, así que b no se ejecuta nunca.
  • En a or b, si a es verdadero el resultado ya es verdadero, así que b no se ejecuta.

Esto no es un detalle de eficiencia, es una herramienta. Te permite comprobar primero que algo es seguro y solo después usarlo:

python
entrada = "hola"

print(entrada.isdigit() and int(entrada) > 100)
Salida en pantalla
False

entrada.isdigit() es False, así que Python se detiene ahí y nunca ejecuta int("hola"), que habría dado un ValueError. Compruébalo quitando la protección:

python
entrada = "hola"

print(int(entrada) > 100)
Salida en pantalla
ValueError: invalid literal for int() with base 10: 'hola'

El mismo patrón sirve para no pasarse del final de una cadena:

python
linea = ""
resultado = linea and linea[0] == "#"
print(f"{resultado=}")

linea = "# comentario"
resultado = linea and linea[0] == "#"
print(f"{resultado=}")
Salida en pantalla
resultado=''
resultado=True

Con la cadena vacía, que es falsa, Python se detiene en el primer operando y linea[0] no llega a ejecutarse; el resultado es la propia cadena vacía, que en un if cuenta como falso. Sin la protección delante, el mismo código se cae:

python
linea = ""

print(linea[0] == "#")
Salida en pantalla
IndexError: string index out of range

Y para no dividir entre cero:

python
divisor = 0

print(divisor != 0 and 100 / divisor > 10)
Salida en pantalla
False

Con esto ya puedes escribir un validador de una sola línea:

validador.py
edad_texto = input("Edad: ").strip()

if edad_texto.isdigit() and 18 <= int(edad_texto) <= 120:
        print(f"Edad registrada: {int(edad_texto)}")
else:
        print("Edad no válida: escribe un número entero entre 18 y 120.")
Salida en pantalla
Edad: treinta
Edad no válida: escribe un número entero entre 18 y 120.

and y or no devuelven True o False#

Mira con atención la salida de esto:

python
print("hola" and "mundo")
print("" or "sin nombre")
print(0 or 10)
print("Erwin" or "anónimo")
print(None and "nunca")
Salida en pantalla
mundo
sin nombre
10
Erwin
None

No ha salido ni un True ni un False. Lo que devuelven and y or es uno de los dos operandos, el que ha decidido el resultado:

  • or devuelve el primero que sea verdadero, y si ninguno lo es, el último.
  • and devuelve el primero que sea falso, y si ninguno lo es, el último.

En un if no lo notas, porque el if convierte a booleano de todas formas. Pero fuera de un if da un atajo muy usado en Python, el valor por defecto:

python
nombre = ""
nombre_mostrado = nombre or "Invitado"

print(f"Hola, {nombre_mostrado}")
Salida en pantalla
Hola, Invitado

Si nombre tiene contenido se queda con él; si está vacío, coge "Invitado". Una línea en lugar de cuatro de if/else.