Operadores en Python — teoría con la cafetería de la facultad, // y % para repartir y un 0.1 + 0.2 que no da 0.3 (y la cuenta del bocadillo que nunca cuadraba)
La primera vez que usé Python para algo «de verdad» fue en la cafetería de la facultad. Laura y yo habíamos pedido un café (1,10 €) y un bocadillo (2,20 €), pusimos 3,30 € en la mesa y, como acabábamos de ver variables en FP1, escribí un programa de cinco líneas para comprobar que estaba bien pagado. Esto es lo que hice:
# Mi primer «programa de la cafetería»: pagar a medias un café y un bocadillo
cafe = 1.10 # euros
bocadillo = 2.20
total = cafe + bocadillo
print("Total:", total)
pagado = 3.30 # lo que pusimos en la mesa, contado a mano
print("¿Pagado justo?", pagado == total)
por_persona = total / 2
print("Cada uno:", por_persona)
Y esto es lo que me contestó Python:
Total: 3.3000000000000003 ¿Pagado justo? False Cada uno: 1.6500000000000001
¿3.3000000000000003? ¿Que no habíamos pagado justo? ¿Y 1.6500000000000001 cada uno? Ni el ordenador estaba roto ni Python sabe sumar mal: el problema estaba en cómo había usado los operadores. + y / sobre decimales, y un == para comparar dos números que «parecen» iguales pero no lo son. Al terminar este artículo sabrás exactamente qué pasó y las tres formas de evitarlo.
En el artículo de variables y tipos de datos aprendiste a guardar datos en cajas con nombre (int, float, str, bool) y te dejé dos promesas: explicarte //, % y ** (y por qué 5 / 2 da 2.5) y enseñarte a comparar decimales con seguridad. Hoy toca cumplirlas. Vamos a ver todos los operadores que necesitas en primero: aritméticos, de comparación, lógicos y de asignación compuesta, y el orden en que Python los aplica. Todo con la cafetería de la facultad como ejemplo: precios, croissants que hay que repartir en bandejas y la caja que se va llenando a lo largo de la mañana. Después, en la práctica, los usarás en tres programas completos.
Tabla de Contenidos
¿Qué es un operador en Python?
Un operador es un símbolo que le dice a Python qué hacer con uno o varios valores. En 3 + 5, el + es el operador y 3 y 5 son sus operandos. Todo junto (3 + 5) es una expresión, y una expresión siempre se reduce a un único valor: 8.
Fíjate en una cosa que parece una tontería y no lo es: el resultado de una expresión tiene un tipo. 3 + 5 da un int, 5 / 2 da un float y 5 > 3 da un bool. Saber qué tipo sale de cada operador te ahorra la mitad de los errores de este tema.
| Familia | Operadores | Qué devuelven | Ejemplo |
|---|---|---|---|
| Aritméticos | + - * / // % ** | Un número | 120 + 95 → 215 |
| Comparación | == != < > <= >= | True o False | 120 < 150 → True |
| Lógicos | and or not | Uno de sus operandos (normalmente un bool) | True and False → False |
| Asignación compuesta | += -= *= /= //= %= **= | Nada: cambian una variable | caja += 120 |
Los iremos viendo en este orden, que además es el orden en el que los vas a usar: primero cuentas, luego comparas y luego combinas comparaciones.
Operadores aritméticos en Python: los del día a día
Son siete. Para verlos con datos reales, voy a usar los precios de la cafetería en céntimos (un café cuesta 120 céntimos, un croissant 95). Más adelante verás que trabajar en céntimos no es una manía mía: es la forma profesional de manejar dinero.
# Los siete operadores aritméticos con precios de la cafetería, en céntimos
cafe = 120 # 1,20 €
croissant = 95 # 0,95 €
# f"{expresion = }" imprime la expresión tal cual y su resultado
print(f"{cafe + croissant = }") # suma
print(f"{cafe - croissant = }") # resta
print(f"{3 * cafe = }") # producto
print(f"{cafe / 2 = }") # división real: SIEMPRE da float
print(f"{cafe // 50 = }") # cociente entero: monedas de 50 que caben
print(f"{cafe % 50 = }") # resto: lo que queda después de esas monedas
print(f"{2 ** 10 = }") # potencia
print(f"{9 ** 0.5 = }") # exponente 0.5 = raíz cuadrada
Esto es lo que imprime:
cafe + croissant = 215 cafe - croissant = 25 3 * cafe = 360 cafe / 2 = 60.0 cafe // 50 = 2 cafe % 50 = 20 2 ** 10 = 1024 9 ** 0.5 = 3.0
f"{expresion = }", con el = justo antes de cerrar la llave, imprime la expresión tal cual y su resultado. Es perfecto para hacer pruebas rápidas: no tienes que escribir la etiqueta a mano y nunca se desincroniza del cálculo.
Entre líneas:
cafe + croissantycafe - croissanthacen lo que esperas: 120 + 95 = 215 y 120 − 95 = 25. Como los dos operandos sonint, el resultado también esint.3 * cafemultiplica: tres cafés son 360 céntimos.cafe / 2es la división de siempre, la de la calculadora. Fíjate en que da60.0, con su.0, aunque 120 entre 2 sea exacto. Ahora vemos por qué.cafe // 50es el cociente entero: cuántas monedas de 50 céntimos caben enteras en un café. Caben 2 (2 × 50 = 100).cafe % 50es el resto: lo que queda después de poner esas dos monedas. 120 − 100 = 20.2 ** 10es la potencia: 2 elevado a 10, 1024. Y9 ** 0.5es un truco que conviene conocer: elevar a 0.5 es hacer la raíz cuadrada, así que da3.0.
Error clásico 1: confundir / con //
Este es el error que más veces he visto en los ejercicios de FP1, y la promesa que te dejé en el artículo de variables: ¿por qué 5 / 2 da 2.5? Porque en Python 3 el operador / es siempre la división real: el resultado es un float, haya decimales o no. Si vienes de C o de Java, donde 5 / 2 entre enteros da 2, esto te va a pillar seguro.
Si lo que quieres es saber cuántas veces cabe un número en otro, necesitas //. Vamos a repartir 17 croissants en bandejas de 5:
# Repartir 17 croissants en bandejas de 5
croissants = 17
por_bandeja = 5
bandejas = croissants // por_bandeja # cuántas bandejas se llenan enteras
sobran = croissants % por_bandeja # cuántos quedan sueltos
print(bandejas, "bandejas llenas y sobran", sobran)
print("Comprobación:", bandejas * por_bandeja + sobran) # tiene que volver a dar 17
print("divmod hace las dos cosas:", divmod(croissants, por_bandeja))
# Con / cambia el tipo y el significado: 3.4 bandejas no se pueden llevar
print("17 / 5 =", croissants / por_bandeja)
print("10 / 2 =", 10 / 2, type(10 / 2)) # exacta, pero float igualmente
print("10 // 2 =", 10 // 2, type(10 // 2))
print("7.5 // 2 =", 7.5 // 2) # si un operando es float, // da float
# // redondea hacia ABAJO (hacia menos infinito), no hacia el cero
print("-7 // 2 =", -7 // 2)
print("-7 % 2 =", -7 % 2)
print("int(-7 / 2) =", int(-7 / 2)) # int() corta los decimales: hacia el cero
Salida real:
3 bandejas llenas y sobran 2 Comprobación: 17 divmod hace las dos cosas: (3, 2) 17 / 5 = 3.4 10 / 2 = 5.0 <class 'float'> 10 // 2 = 5 <class 'int'> 7.5 // 2 = 3.0 -7 // 2 = -4 -7 % 2 = 1 int(-7 / 2) = -3
Las cuatro primeras líneas de la salida son las que más vas a usar en tu vida:
17 // 5da3: se llenan 3 bandejas enteras.17 % 5da2: sobran 2 croissants sueltos.- La comprobación
bandejas * por_bandeja + sobranvuelve a dar 17 (3 × 5 + 2 = 17). Esta igualdad se cumple siempre, y es la mejor forma de entender qué son//y%: el cociente y el resto de la división de primaria. divmod(17, 5)hace las dos cosas a la vez y devuelve la pareja(3, 2). Lo usarás en los ejercicios para dar el cambio.
En cambio, 17 / 5 da 3.4, que es una respuesta correcta a otra pregunta: no puedes llevar 3,4 bandejas a la barra. Y fíjate en las líneas de type: 10 / 2 da 5.0 de tipo float, mientras que 10 // 2 da 5 de tipo int. Mismo valor, distinto tipo.
Mira el dibujo: arriba, el reparto de los croissants; abajo, lo que pasa con los números negativos, que es donde // engaña.
| Quiero… | Operador | Ejemplo | Resultado |
|---|---|---|---|
| Una media, un precio por persona, un porcentaje | / | 120 / 2 | 60.0 (float) |
| Cuántos grupos completos caben | // | 17 // 5 | 3 |
| Lo que sobra después de repartir | % | 17 % 5 | 2 |
| Las dos cosas a la vez | divmod | divmod(17, 5) | (3, 2) |
// no quita los decimales: redondea hacia abajo. Con positivos es lo mismo, pero -7 // 2 da -4, no -3, porque −3,5 hacia abajo es −4. Si lo que quieres es cortar los decimales (ir hacia el cero), usa int(-7 / 2), que da -3. Y si un operando es float, // devuelve float: 7.5 // 2 da 3.0.
Error clásico 2: el operador % no es porcentaje
Cuando ves % en Python, no significa «por ciento». Significa módulo, el resto de la división entera. 120 % 50 no es «el 50 % de 120» (que sería 60), es lo que sobra al quitarle a 120 todas las veces que cabe 50: 20.
¿Para qué sirve algo tan raro? Para muchísimo más de lo que parece:
- Par o impar:
n % 2 == 0esTruesines par. Si el resto de dividir entre 2 es 0, no sobra nada. - Divisible entre otro:
15 % 3 == 0esTrue;16 % 3 == 0esFalse(sobra 1). - La última cifra de un número:
2847 % 10es7. Y2847 // 10quita esa última cifra (284). Combinando los dos sacarás todas las cifras en los ejercicios. - Dar formato a dinero: si tienes 1091 céntimos,
1091 // 100son 10 euros y1091 % 100son 91 céntimos. Lo harás en la práctica.
Para calcular un porcentaje de verdad, multiplica y divide: el 15 % de 1200 es 1200 * 15 / 100 (o 1200 * 15 // 100 si quieres un entero).
Con negativos, el resto de Python lleva el signo del divisor: -7 % 2 da 1, y 5 % -2 da -1. Parece caprichoso, pero es lo que hace que b * (a // b) + a % b == a se cumpla siempre: 2 × (−4) + 1 = −7. En la práctica lo comprobarás con −17 y 5.
Operadores de comparación: devuelven True o False
Los operadores de comparación preguntan algo sobre dos valores y responden con un bool: True o False. Son la base de todas las decisiones que tomarás en el siguiente tema.
| Operador | Significa | Ejemplo con precio = 120 | Resultado |
|---|---|---|---|
== | igual a | precio == 120 | True |
!= | distinto de | precio != 100 | True |
< | menor que | precio < 150 | True |
> | mayor que | precio > 150 | False |
<= | menor o igual que | precio <= 120 | True |
>= | mayor o igual que | precio >= 200 | False |
# Operadores de comparación: siempre devuelven True o False
precio = 120 # céntimos
presupuesto = 150
print(f"{precio < presupuesto = }")
print(f"{precio == 120 = }")
print(f"{precio != 100 = }") # != significa «distinto de»
print(f"{0 <= precio <= 200 = }") # comparación encadenada: dentro del rango
print(f"{'cafe' == 'Cafe' = }") # las mayúsculas cuentan
print(f"{5 == 5.0 = }") # int y float con el mismo valor: iguales
print(f"{'5' == 5 = }") # texto frente a número: False, sin error
print(f"{'cafe' < 'zumo' = }") # textos: orden alfabético
Y el resultado:
precio < presupuesto = True precio == 120 = True precio != 100 = True 0 <= precio <= 200 = True 'cafe' == 'Cafe' = False 5 == 5.0 = True '5' == 5 = False 'cafe' < 'zumo' = True
Lo que merece la pena mirar dos veces:
0 <= precio <= 200es una comparación encadenada: Python la lee como0 <= precio and precio <= 200. Sirve para comprobar si un valor está dentro de un rango, y es mucho más legible que la versión conand.'cafe' == 'Cafe'esFalse: para Python, una mayúscula es otro carácter. Si comparas lo que escribe un usuario, normalízalo antes.5 == 5.0esTrue: uninty unfloatcon el mismo valor son iguales.'5' == 5esFalsey no da error: un texto nunca es igual a un número. Es justo el fallo silencioso del artículo de variables, cuando un dato llega deinput()como texto y lo comparas con un número.'cafe' < 'zumo'esTrue: los textos se comparan por orden alfabético (en realidad, carácter a carácter según su código).
Distinto de en Python: el operador !=
Mucha gente busca cómo se escribe «distinto de» o «diferente de» en Python. Es !=, un signo de exclamación pegado a un igual. Se lee «no es igual a» y devuelve lo contrario que ==: precio != 100 es True porque 120 no es 100. No existe <> (en Python 2 sí existía; en Python 3 da SyntaxError) ni =!.
Un uso muy típico: divisor != 0 antes de dividir, que verás enseguida con los operadores lógicos.
Error clásico 3: confundir = con ==
= guarda un valor en una variable. == pregunta si dos valores son iguales. Se parecen tanto que, con prisa, se escapa uno por otro. Mira qué pasa si en una condición escribes = en lugar de ==:
precio = 120
if precio = 120:
print("Es un café")
Al ejecutarlo:
File "asignar.py", line 2
if precio = 120:
^^^^^^^^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?
La buena noticia es que Python 3 te lo dice con todas las letras: «Maybe you meant ‘==’ … instead of ‘=’?». Las flechitas ^^^^ señalan la parte que no entiende. La mala noticia es que en otros sitios el error no salta: si escribes precio == 120 en una línea suelta queriendo asignar, Python compara, no guarda nada y sigue tan tranquilo.
Léelo en voz alta. = se lee «vale» o «guarda» (precio = 120: precio vale 120). == se lee «¿es igual a?» (precio == 120: ¿precio es igual a 120?). Si la frase es una pregunta, son dos iguales.
Comparar decimales con seguridad: por qué 0.1 + 0.2 no da 0.3
Volvamos al gancho. El ticket no cuadraba porque 1.10 + 2.20 daba 3.3000000000000003. El caso más famoso del mismo problema es este:
import math
# El problema: 0.1 y 0.2 no se pueden guardar exactos en binario
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
# Con 20 decimales se ve lo que hay guardado de verdad
print(f"{0.1:.20f}")
print(f"{0.2:.20f}")
print(f"{0.1 + 0.2:.20f}")
print(f"{0.3:.20f}")
# Solución 1: redondear antes de comparar
print(round(0.1 + 0.2, 2) == 0.3)
# Solución 2: math.isclose compara con un margen de tolerancia
print(math.isclose(0.1 + 0.2, 0.3))
print(math.isclose(1.10 + 2.20, 3.30)) # el ticket del gancho
# Solución 3: trabajar en céntimos (enteros, que son exactos)
print(10 + 20 == 30)
print(110 + 220 == 330)
Esto es lo que imprime:
0.30000000000000004 False 0.10000000000000000555 0.20000000000000001110 0.30000000000000004441 0.29999999999999998890 True True True True True
¿Qué está pasando? El ordenador guarda los float en binario, y en binario 0,1 no tiene una representación exacta: es como 1/3 en decimal (0,3333…), que nunca termina. Así que Python guarda el número más cercano que puede. Con 20 decimales lo ves: 0.1 es en realidad 0.10000000000000000555 y 0.2 es 0.20000000000000001110. Al sumarlos, los errorcitos se suman y el resultado (0.30000000000000004441) no cae en el mismo sitio que el 0.3 que escribes a mano (0.29999999999999998890).
Como ves en el dibujo, la diferencia es minúscula (unos 0,00000000000000005), pero == exige que los dos valores sean exactamente el mismo punto de la recta. Por eso da False. Y no es un fallo de Python: pasa igual en Java, en C, en JavaScript y en tu calculadora científica si mira suficientes decimales.
Tienes tres formas de defenderte, y las tres aparecen en el programa:
- Redondear antes de comparar:
round(0.1 + 0.2, 2) == 0.3daTrue. Sirve cuando sabes cuántos decimales importan (dos, en dinero). - Comparar con margen:
math.isclose(a, b)devuelveTruesi los dos números están lo bastante cerca. Hay que hacerimport mathal principio. Es la forma correcta de comparar resultados de cálculos con decimales, y es la que arregla el ticket del gancho:math.isclose(1.10 + 2.20, 3.30)daTrue. - No usar decimales: trabajar en céntimos, con enteros.
110 + 220 == 330es exacto siempre, porque losintno tienen este problema. Es lo que hacen los bancos y las tiendas online, y lo que harás en la práctica.
| Situación | Qué usar | Ejemplo |
|---|---|---|
| Dinero | Céntimos (int) | 110 + 220 == 330 |
| Resultados de cálculos con decimales | math.isclose | math.isclose(media, 7.3) |
| Solo importan unos decimales | round | round(total, 2) == 3.3 |
| Mostrar en pantalla | Formato, no round | f"{total:.2f}" → 3.30 |
Nunca compares dos float con == (ni con !=) si vienen de una cuenta. Funcionará con unos datos y fallará con otros, y ese tipo de error es el peor de encontrar.
Operadores lógicos: and, or y not
Las comparaciones responden preguntas sueltas. Para combinarlas («¿está abierta y no hay cola?») se usan los operadores lógicos:
a | b | a and b | a or b | not a |
|---|---|---|---|---|
True | True | True | True | False |
True | False | False | True | False |
False | True | False | True | True |
False | False | False | False | True |
En resumen: and solo es verdadero si los dos lo son; or es verdadero si al menos uno lo es; not le da la vuelta. Hasta aquí, lo que viene en cualquier libro. Ahora viene lo que casi nadie explica en primero:
# Operadores lógicos con el estado de la cafetería
abierta = True
hay_cola = False
print(f"{abierta and not hay_cola = }") # ¿entro ya?
print(f"{abierta or hay_cola = }")
print(f"{not abierta = }")
# and y or no devuelven siempre True/False: devuelven uno de sus operandos
nombre = "" # el cliente no dio su nombre
print(f"{nombre or 'Anónimo' = }") # "" es falso: or devuelve el segundo
print(f"{'Laura' or 'Anónimo' = }") # "Laura" es verdadero: se queda con él
print(f"{0 or 5 = }", f"{3 and 7 = }", f"{'' and 99 = }")
# Cortocircuito: si la izquierda ya decide, la derecha NO se evalúa
clientes = 0
caja = 0
print(f"{clientes != 0 and caja / clientes > 5 = }") # no llega a dividir
print(f"{caja / clientes > 5 and clientes != 0 = }") # divide primero: error
Salida real:
abierta and not hay_cola = True
abierta or hay_cola = True
not abierta = False
nombre or 'Anónimo' = 'Anónimo'
'Laura' or 'Anónimo' = 'Laura'
0 or 5 = 5 3 and 7 = 7 '' and 99 = ''
clientes != 0 and caja / clientes > 5 = False
Traceback (most recent call last):
File "logicos.py", line 19, in <module>
print(f"{caja / clientes > 5 and clientes != 0 = }") # divide primero: error
~~~~~^~~~~~~~~~
ZeroDivisionError: division by zero
and y or devuelven valores, no solo True o False
Fíjate en nombre or 'Anónimo': no da True ni False, da 'Anónimo'. Esto es porque en Python and y or devuelven uno de sus operandos:
x or y: sixes «verdadero», devuelvex; si no, devuelvey.x and y: sixes «falso», devuelvex; si no, devuelvey.
¿Y qué es «verdadero» o «falso» para algo que no es un bool? Lo viste en el artículo de variables con bool(): son falsos el 0, el 0.0, el texto vacío "" y None; casi todo lo demás es verdadero. Así:
nombre or 'Anónimo'connombre = ""devuelve'Anónimo', porque el texto vacío es falso. Con'Laura', devuelve'Laura'. Es la forma más corta de poner un valor por defecto.0 or 5da5;3 and 7da7(el 3 es verdadero, así queanddevuelve el segundo);'' and 99da''(el texto vacío es falso yandse queda con él).
Cuando los operandos son bool, como en abierta and not hay_cola, todo esto da igual: el resultado es True o False de toda la vida.
Evaluación en cortocircuito
Las dos últimas líneas del programa son las más importantes. Con clientes = 0:
clientes != 0 and caja / clientes > 5daFalsesin dar error. Python mira primero la izquierda:clientes != 0esFalse, y «falso and lo que sea» es falso. Así que ni siquiera evalúa la derecha. La división entre cero nunca llega a ocurrir.caja / clientes > 5 and clientes != 0tiene las mismas piezas al revés, y revienta conZeroDivisionError: Python empieza por la izquierda, intenta dividir entre cero y se para ahí.
Esto se llama evaluación en cortocircuito: and se para en cuanto encuentra algo falso y or se para en cuanto encuentra algo verdadero. No es un detalle de examen: es una herramienta. Pon primero la comprobación que protege (divisor != 0, «la lista no está vacía»…) y después la operación peligrosa.
| Operador | Se para cuando la izquierda es… | Y entonces devuelve… |
|---|---|---|
and | falsa | la izquierda |
or | verdadera | la izquierda |
Escribir metodo == "efectivo" or "bizum" para preguntar «¿es efectivo o bizum?». Python lo lee como (metodo == "efectivo") or "bizum", y como "bizum" es un texto no vacío (verdadero), el resultado nunca es falso. Hay que repetir la comparación: metodo == "efectivo" or metodo == "bizum". Lo destripamos en los ejercicios.
Operadores de asignación compuesta: el atajo que ahorra tiempo
Muchas veces quieres cambiar una variable a partir de su propio valor: sumarle una venta a la caja, contar un café más. Escribir caja = caja + 120 funciona, pero Python tiene un atajo: caja += 120. Hay uno por cada operador aritmético.
# La caja de la cafetería a lo largo de la mañana (céntimos)
caja = 0
cafes = 0
caja += 120 # un café (caja = caja + 120)
cafes += 1
caja += 95 # un croissant
caja += 120 # otro café
cafes += 1
caja -= 50 # devolvemos 50 céntimos de un cambio mal dado
print("Caja:", caja, "| cafés vendidos:", cafes)
caja *= 2 # «¿y si toda la mañana fuera así?»
print("El doble:", caja)
caja //= 3 # repartir entre 3 turnos (entero)
print("Por turno:", caja)
caja /= 2 # /= convierte a float, aunque la cuenta sea exacta
print("Media hora:", caja, type(caja))
Y el resultado:
Caja: 285 | cafés vendidos: 2 El doble: 570 Por turno: 190 Media hora: 95.0 <class 'float'>
Así evoluciona la caja línea a línea (la tabla de traza que te recomiendo hacer siempre que una variable cambie varias veces):
| Línea | Operación | caja después | cafes después |
|---|---|---|---|
| inicio | caja = 0, cafes = 0 | 0 | 0 |
| café | caja += 120, cafes += 1 | 120 | 1 |
| croissant | caja += 95 | 215 | 1 |
| café | caja += 120, cafes += 1 | 335 | 2 |
| devolución | caja -= 50 | 285 | 2 |
| el doble | caja *= 2 | 570 | 2 |
| tres turnos | caja //= 3 | 190 | 2 |
| media hora | caja /= 2 | 95.0 | 2 |
Las cuentas: 120 + 95 + 120 − 50 = 285; 285 × 2 = 570; 570 // 3 = 190 (exacto); 190 / 2 = 95.0. Fíjate en la última línea de la salida: después de /=, la caja ya es un float, igual que pasaba con /. Los atajos se comportan exactamente como el operador que llevan dentro.
+= es el operador que más vas a escribir en FP1: todos los contadores (cafes += 1) y acumuladores (total += precio) de los bucles lo usan. Y funciona también con textos: mensaje += "!" añade una exclamación al final.
Usar += con una variable que todavía no existe. ventas += 1 sin haber escrito antes ventas = 0 da NameError, porque Python necesita el valor anterior para sumarle 1. Inicializa siempre los contadores.
Precedencia de operadores: el orden importa
Cuando en una expresión hay varios operadores, ¿cuál va primero? Igual que en matemáticas, la multiplicación va antes que la suma. Pero Python tiene más operadores que las matemáticas del colegio, y algunos casos sorprenden:
# Precedencia: qué se calcula primero cuando hay varios operadores
print(3 + 8 * 2) # * antes que +
print((3 + 8) * 2) # los paréntesis mandan
print(-2 ** 2) # ** antes que el - de delante: -(2 ** 2)
print((-2) ** 2)
print(2 ** 3 ** 2) # ** se agrupa de derecha a izquierda: 2 ** 9
print(10 - 4 - 3) # mismo nivel: de izquierda a derecha
print(17 % 10 // 2) # % y // también: (17 % 10) // 2
# El ticket: 3 cafés, 2 croissants y un vale de 50 céntimos a medias
total = 3 * 120 + 2 * 95 - 50 // 2
print("Total:", total)
print(True or False and False) # and antes que or
print(not 120 == 100) # not se aplica después de ==
Al ejecutarlo:
19 22 -4 4 512 3 3 Total: 525 True True
Línea a línea:
3 + 8 * 2da 19, no 22: primero 8 × 2 = 16 y luego 3 + 16. Con paréntesis,(3 + 8) * 2sí da 22.-2 ** 2da −4. Es la trampa más famosa:**tiene más prioridad que el signo menos de delante, así que Python calcula −(2²). Si quieres el cuadrado de −2, escribe(-2) ** 2, que da 4.2 ** 3 ** 2da 512:**es el único operador aritmético que se agrupa de derecha a izquierda, así que es 2 ** (3 ** 2) = 2 ** 9.10 - 4 - 3da 3: dentro del mismo nivel se va de izquierda a derecha, (10 − 4) − 3. Si fuera de derecha a izquierda daría 9.17 % 10 // 2da 3:%y//están en el mismo escalón, así que primero 17 % 10 = 7 y luego 7 // 2 = 3.True or False and Falseda True:andva antes queor, así que esTrue or (False and False).not 120 == 100da True:notva después de las comparaciones, así que esnot (120 == 100).
Y el ticket: 3 cafés, 2 croissants y un vale de 50 céntimos que pagamos a medias. Mira en el dibujo cómo se resuelve paso a paso y en qué escalón está cada operador:
Las cuentas a mano: 3 × 120 = 360; 2 × 95 = 190; 50 // 2 = 25; 360 + 190 = 550; 550 − 25 = 525. Primero todos los * y // (de izquierda a derecha) y después la suma y la resta.
| Nivel (de más a menos prioridad) | Operadores |
|---|---|
| 1 | ( ) paréntesis |
| 2 | ** (de derecha a izquierda) |
| 3 | -x, +x (signo) |
| 4 | * / // % |
| 5 | + - |
| 6 | == != < > <= >= |
| 7 | not |
| 8 | and |
| 9 | or |
No hace falta memorizar la tabla entera. Con saber que ** va antes que el signo, que las comparaciones van antes que not, and y or (en ese orden) y que en caso de duda se ponen paréntesis, tienes el 99 % de los casos. Un paréntesis de más nunca rompe nada y hace el código más fácil de leer.
Errores típicos con los operadores
Resumen de los que hemos ido viendo, para que los tengas juntos:
Usar / cuando necesitas un número entero de algo (bandejas, mesas, grupos). / siempre da float; usa // y, para lo que sobra, %.
Pensar que % es «por ciento». Es el resto de la división. El porcentaje se calcula con * porcentaje / 100.
Comparar float con ==. Usa céntimos, math.isclose o round.
Olvidar paréntesis en las medias: a + b + c / 3 solo divide c. Lo correcto es (a + b + c) / 3.
-2 ** 2 da −4. Si el número negativo es la base, va entre paréntesis.
Míralo paso a paso en Python Tutor
Python Tutor ejecuta tu código línea a línea y dibuja cada variable con su valor en cada momento. Copia este programa, elige Python 3 y pulsa Visualize Execution:
precio = 120 cantidad = 3 vale = 50 subtotal = cantidad * precio total = subtotal - vale // 2 # // antes que - media = total / cantidad # / siempre da float justo = media * cantidad == total clientes = 0 ok = clientes != 0 and total / clientes > 100 # no llega a dividir nombre = "" cliente = nombre or "Anónimo" # or devuelve un valor, no un bool print(total, media, justo, ok, cliente)
Salida:
335 111.66666666666667 True False Anónimo
Qué observar paso a paso:
- Al ejecutar
total = subtotal - vale // 2,totalaparece directamente con 335. Python no guarda el resultado devale // 2en ninguna variable: lo calcula (25) antes de la resta, por precedencia, y lo usa al momento. 360 − 25 = 335. mediaaparece como111.66666666666667: unfloat, aunque todos los operandos eranint. Es el/.justosaleTrue: aquímedia * cantidadvuelve a dar exactamente 335.0. No siempre tendrás esa suerte con los decimales; por eso existemath.isclose.- Cuando llegues a la línea de
ok, fíjate en que el programa avanza sin error aunqueclientesvale 0:clientes != 0esFalsey elandya no evalúa la división. Cambia el orden de las dos partes y verás elZeroDivisionErroren directo. clientevale'Anónimo', noTrue:orha devuelto su segundo operando porquenombreera un texto vacío.
Resumen
| Operador | Qué hace | Ejemplo | Resultado |
|---|---|---|---|
/ | División real (siempre float) | 5 / 2 | 2.5 |
// | Cociente entero (hacia abajo) | 17 // 5 | 3 |
% | Resto | 17 % 5 | 2 |
** | Potencia | 2 ** 10 | 1024 |
==, != | Igual, distinto | 120 != 100 | True |
<= encadenado | Dentro de un rango | 0 <= 120 <= 200 | True |
and, or | Combinar, con cortocircuito | "" or "Anónimo" | 'Anónimo' |
not | Negar | not True | False |
+= y compañía | Cambiar una variable a partir de su valor | caja += 120 | caja aumenta 120 |
math.isclose | Comparar decimales con margen | math.isclose(0.1 + 0.2, 0.3) | True |
Tres ideas para llevarte:
- Cada operador devuelve un tipo.
/dafloatsiempre,//y%dan el cociente y el resto (yb * (a // b) + a % b == a), y las comparaciones danbool. - Nunca compares decimales con
==. Trabaja en céntimos cuando sea dinero y usamath.isclosecuando sean cálculos. andyorse paran en cuanto saben la respuesta y devuelven uno de sus operandos. Pon delante la comprobación que protege y, ante la duda sobre el orden, paréntesis.
Con los operadores de comparación y los lógicos ya tienes todo lo necesario para que tus programas tomen decisiones. Eso es justo lo que viene después: en Condicionales en Python usarás estas mismas expresiones (nota >= 5 and asistencia >= 75, divisor != 0…) dentro de if, elif y else. Pero antes, ponlos a trabajar en la práctica de operadores: un conversor de unidades, el bono de cafés con IGIC en céntimos y una calculadora que no se rompe con negativos.
¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




Qué es un sistema operativo — teoría con tu portátil en una tarde de estudio, una llamada a write() y la CPU que nunca descansa (y los tres programas que no se ejecutaban a la vez)