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.

¿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.

FamiliaOperadoresQué devuelvenEjemplo
Aritméticos+ - * / // % **Un número120 + 95 → 215
Comparación== != < > <= >=True o False120 < 150 → True
Lógicosand or notUno de sus operandos (normalmente un bool)True and False → False
Asignación compuesta+= -= *= /= //= %= **=Nada: cambian una variablecaja += 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 + croissant y cafe - croissant hacen lo que esperas: 120 + 95 = 215 y 120 − 95 = 25. Como los dos operandos son int, el resultado también es int.
  • 3 * cafe multiplica: tres cafés son 360 céntimos.
  • cafe / 2 es la división de siempre, la de la calculadora. Fíjate en que da 60.0, con su .0, aunque 120 entre 2 sea exacto. Ahora vemos por qué.
  • cafe // 50 es el cociente entero: cuántas monedas de 50 céntimos caben enteras en un café. Caben 2 (2 × 50 = 100).
  • cafe % 50 es el resto: lo que queda después de poner esas dos monedas. 120 − 100 = 20.
  • 2 ** 10 es la potencia: 2 elevado a 10, 1024. Y 9 ** 0.5 es un truco que conviene conocer: elevar a 0.5 es hacer la raíz cuadrada, así que da 3.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 // 5 da 3: se llenan 3 bandejas enteras.
  • 17 % 5 da 2: sobran 2 croissants sueltos.
  • La comprobación bandejas * por_bandeja + sobran vuelve 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.

Cociente entero, resto y redondeo hacia abajoArriba, 17 croissants repartidos en 3 bandejas de 5 y 2 sueltos: 17 // 5 es 3 y 17 % 5 es 2. Abajo, una recta numérica: 3.4 baja a 3; -3.5 baja a -4 con //, mientras que int() lo corta a -3.17 croissants en bandejas de 5bandeja 1bandeja 2bandeja 3sueltos17 // 5 = 3 bandejas llenas17 % 5 = 2 sobran17 / 5 = 3.4 (no hay 0,4 bandejas)// redondea hacia ABAJO, también con negativos-5-4-3-2-10123453.417 // 5 → 3-3.5-7 // 2 → -4 // (suelo)int(-7 / 2) → -3 int() (hacia el 0)
// cuenta las bandejas llenas y % los que sobran; con negativos, // sigue bajando hacia la izquierda.
Quiero…OperadorEjemploResultado
Una media, un precio por persona, un porcentaje/120 / 260.0 (float)
Cuántos grupos completos caben//17 // 53
Lo que sobra después de repartir%17 % 52
Las dos cosas a la vezdivmoddivmod(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 == 0 es True si n es par. Si el resto de dividir entre 2 es 0, no sobra nada.
  • Divisible entre otro: 15 % 3 == 0 es True; 16 % 3 == 0 es False (sobra 1).
  • La última cifra de un número: 2847 % 10 es 7. Y 2847 // 10 quita 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 // 100 son 10 euros y 1091 % 100 son 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.

OperadorSignificaEjemplo con precio = 120Resultado
==igual aprecio == 120True
!=distinto deprecio != 100True
<menor queprecio < 150True
>mayor queprecio > 150False
<=menor o igual queprecio <= 120True
>=mayor o igual queprecio >= 200False
# 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 <= 200 es una comparación encadenada: Python la lee como 0 <= 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 con and.
  • 'cafe' == 'Cafe' es False: para Python, una mayúscula es otro carácter. Si comparas lo que escribe un usuario, normalízalo antes.
  • 5 == 5.0 es True: un int y un float con el mismo valor son iguales.
  • '5' == 5 es False y 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 de input() como texto y lo comparas con un número.
  • 'cafe' < 'zumo' es True: 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).

Por qué 0.1 + 0.2 no es igual a 0.30.1 y 0.2 no se pueden guardar exactos en binario. La suma queda en 0.30000000000000004441 y el 0.3 escrito a mano en 0.29999999999999998890: son dos puntos distintos de la recta, separados por una diferencia minúscula. == los ve distintos; math.isclose los acepta porque caen dentro de su margen.Lo que hay guardado de verdad (20 decimales)0.1 se guarda como0.100000000000000005550.2 se guarda como0.20000000000000001110margen de math.isclose: los dos caen dentro0.3 escrito a mano0.299999999999999988900.1 + 0.20.30000000000000004441diferencia ≈ 0.000000000000000055510.1 + 0.2 == 0.3 → Falsemath.isclose(0.1 + 0.2, 0.3) → True10 + 20 == 30 → True (céntimos)
== exige el mismo punto exacto; math.isclose acepta una banda alrededor, y los céntimos enteros no tienen el problema.

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:

  1. Redondear antes de comparar: round(0.1 + 0.2, 2) == 0.3 da True. Sirve cuando sabes cuántos decimales importan (dos, en dinero).
  2. Comparar con margen: math.isclose(a, b) devuelve True si los dos números están lo bastante cerca. Hay que hacer import math al 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) da True.
  3. No usar decimales: trabajar en céntimos, con enteros. 110 + 220 == 330 es exacto siempre, porque los int no tienen este problema. Es lo que hacen los bancos y las tiendas online, y lo que harás en la práctica.
SituaciónQué usarEjemplo
DineroCéntimos (int)110 + 220 == 330
Resultados de cálculos con decimalesmath.isclosemath.isclose(media, 7.3)
Solo importan unos decimalesroundround(total, 2) == 3.3
Mostrar en pantallaFormato, no roundf"{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:

aba and ba or bnot a
TrueTrueTrueTrueFalse
TrueFalseFalseTrueFalse
FalseTrueFalseTrueTrue
FalseFalseFalseFalseTrue

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: si x es «verdadero», devuelve x; si no, devuelve y.
  • x and y: si x es «falso», devuelve x; si no, devuelve y.

¿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' con nombre = "" 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 5 da 5; 3 and 7 da 7 (el 3 es verdadero, así que and devuelve el segundo); '' and 99 da '' (el texto vacío es falso y and se 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 > 5 da False sin dar error. Python mira primero la izquierda: clientes != 0 es False, 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 != 0 tiene las mismas piezas al revés, y revienta con ZeroDivisionError: 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.

OperadorSe para cuando la izquierda es…Y entonces devuelve…
andfalsala izquierda
orverdaderala 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íneaOperacióncaja despuéscafes después
iniciocaja = 0, cafes = 000
cafécaja += 120, cafes += 11201
croissantcaja += 952151
cafécaja += 120, cafes += 13352
devolucióncaja -= 502852
el doblecaja *= 25702
tres turnoscaja //= 31902
media horacaja /= 295.02

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 * 2 da 19, no 22: primero 8 × 2 = 16 y luego 3 + 16. Con paréntesis, (3 + 8) * 2 sí da 22.
  • -2 ** 2 da −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 ** 2 da 512: ** es el único operador aritmético que se agrupa de derecha a izquierda, así que es 2 ** (3 ** 2) = 2 ** 9.
  • 10 - 4 - 3 da 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 // 2 da 3: % y // están en el mismo escalón, así que primero 17 % 10 = 7 y luego 7 // 2 = 3.
  • True or False and False da True: and va antes que or, así que es True or (False and False).
  • not 120 == 100 da True: not va después de las comparaciones, así que es not (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:

Orden de evaluación de una expresiónA la izquierda, la expresión 3 * 120 + 2 * 95 – 50 // 2 se resuelve en cinco pasos: primero 3 * 120 = 360, luego 2 * 95 = 190, luego 50 // 2 = 25, luego 360 + 190 = 550 y por último 550 – 25 = 525. A la derecha, la escalera de precedencia de Python: **, signo, multiplicativos, suma y resta, comparaciones, not, and y or.El ticket, paso a pasoQuién va primero3 * 120 + 2 * 95 – 50 // 2360 + 2 * 95 – 50 // 2paso 1360 + 190 – 50 // 2paso 2360 + 190 – 25paso 3550 – 25paso 4525paso 51**2-x (signo)3* / // %4+ –5== != < > <= >=6not7and8ormismo nivel: de izquierda a derecha (salvo **)
Primero suben los operadores de arriba de la escalera; dentro del mismo escalón se va de izquierda a derecha.

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== != < > <= >=
7not
8and
9or

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:

  1. Al ejecutar total = subtotal - vale // 2, total aparece directamente con 335. Python no guarda el resultado de vale // 2 en ninguna variable: lo calcula (25) antes de la resta, por precedencia, y lo usa al momento. 360 − 25 = 335.
  2. media aparece como 111.66666666666667: un float, aunque todos los operandos eran int. Es el /.
  3. justo sale True: aquí media * cantidad vuelve a dar exactamente 335.0. No siempre tendrás esa suerte con los decimales; por eso existe math.isclose.
  4. Cuando llegues a la línea de ok, fíjate en que el programa avanza sin error aunque clientes vale 0: clientes != 0 es False y el and ya no evalúa la división. Cambia el orden de las dos partes y verás el ZeroDivisionError en directo.
  5. cliente vale 'Anónimo', no True: or ha devuelto su segundo operando porque nombre era un texto vacío.

Resumen

OperadorQué haceEjemploResultado
/División real (siempre float)5 / 22.5
//Cociente entero (hacia abajo)17 // 53
%Resto17 % 52
**Potencia2 ** 101024
==, !=Igual, distinto120 != 100True
<= encadenadoDentro de un rango0 <= 120 <= 200True
and, orCombinar, con cortocircuito"" or "Anónimo"'Anónimo'
notNegarnot TrueFalse
+= y compañíaCambiar una variable a partir de su valorcaja += 120caja aumenta 120
math.iscloseComparar decimales con margenmath.isclose(0.1 + 0.2, 0.3)True

Tres ideas para llevarte:

  1. Cada operador devuelve un tipo. / da float siempre, // y % dan el cociente y el resto (y b * (a // b) + a % b == a), y las comparaciones dan bool.
  2. Nunca compares decimales con ==. Trabaja en céntimos cuando sea dinero y usa math.isclose cuando sean cálculos.
  3. and y or se 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.

Siguiente paso: prácticaOperadores en Python — práctica con un conversor de unidades, el bono de cafés con IGIC en céntimos y una calculadora con negativos (y el céntimo que se me perdía)

¿Te ha servido este artículo? Así puedes apoyar SergioLearns →

Sigue aprendiendo

Deja una respuesta

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