Operadores en Python — ejercicios con la cuota del gimnasio, segundos a horas y el cambio de la caja moneda a moneda (y un or que siempre decía que sí)
En una práctica de FP1 teníamos que simular la máquina de cobro de la cafetería, y una de las comprobaciones era si el método de pago estaba aceptado. Yo escribí metodo == "efectivo" or "bizum", lo probé con efectivo, lo probé con bizum, funcionaba… y lo entregué. El profesor lo probó con «tarjeta» y la máquina también la aceptó. Y con «piedras». Mi or decía que sí a todo. Tardé un buen rato en entender por qué, y es uno de los tres fragmentos de «¿Qué falla aquí?» de hoy: los operadores no hacen lo que lees, hacen lo que dicen sus reglas.
Estos son los ejercicios del tema de operadores. Antes conviene haber leído la teoría y hecho la práctica. Tienes cinco ejercicios en tres niveles (básico, intermedio y desafío) con especial foco en // y %, que son los que más confunden, tres fragmentos con trampa, las soluciones explicadas línea a línea y, al final, el chuletario para tenerlo todo a mano.
Tabla de Contenidos
Cómo usar este artículo
- Lee el enunciado y la salida esperada. Los datos van fijos en variables al principio (sin
input()), igual que en la práctica. - Intenta resolverlo en tu editor. Si llevas más de 10 minutos atascado, abre la pista.
- Compara con la solución comentada. No solo si da lo mismo: fíjate en por qué está hecha así.
- Cambia los datos (otro número de meses, otra nota, otro importe) y predice la salida antes de ejecutar.
Todos se pueden hacer sin if, solo con operadores: es parte del reto. En el siguiente tema, con los condicionales, verás versiones más cómodas.
Nivel básico
Ejercicio 1: factura del gimnasio
Un gimnasio cobra 29,99 € al mes. Los socios que llevan más de 12 meses tienen un 10 % de descuento a partir del mes 13. Con meses = 15, el programa muestra la cuota base, la cuota de este mes, el total pagado hasta ahora y el ahorro acumulado. Trabaja en céntimos.
Salida esperada:
--- Factura del gimnasio --- Meses como socio: 15 Cuota base: 29,99 € Cuota este mes: 26,99 € Total pagado: 440,85 € Ahorro acumulado: 9,00 €
Separa los meses en dos tramos: los que pagan precio completo y los que tienen descuento (max(0, meses - 12) no deja que salga negativo). Y recuerda que True vale 1 y False vale 0 cuando se multiplican.
Ejercicio 2: conversor de tiempo
Convierte segundos = 3723 a horas, minutos y segundos, y muéstralo también en formato reloj (01:02:03). Comprueba el resultado haciendo la cuenta al revés y repite la conversión con divmod.
Salida esperada:
3723 segundos son: → 1 h, 2 min y 3 s → en formato reloj: 01:02:03 Comprobación: 3723 Con divmod: 1 2 3
Es puro // y %. Las horas son segundos // 3600; lo que sobra de las horas es segundos % 3600, y de eso salen los minutos con // 60. Los segundos sueltos son segundos % 60.
Nivel intermedio
Ejercicio 3: análisis de una nota
Con una nota sobre 100 (nota = 73), muestra si es válida (entre 0 y 100), la nota sobre 10, si está aprobada (≥ 50), si es notable (≥ 70) o sobresaliente (≥ 90), cuál es el siguiente nivel y cuántos puntos faltan para llegar, y cuántos puntos tiene por encima del aprobado. Sin if.
Salida esperada:
--- Análisis de la nota 73 --- ¿Nota válida? True Sobre 10: 7.3 ¿Aprobado? True | ¿Notable? True | ¿Sobresaliente? False Siguiente nivel: Sobresaliente (faltan 17 puntos) Puntos sobre el aprobado: 23
(nota < 70 and "Notable") vale "Notable" si la nota es menor que 70 y False si no. Encadena varios así con or: el primero que no sea falso es el que se queda.
Ejercicio 4: extractor de dígitos
Con n = 2847, saca cada cifra por separado sin convertir el número a texto, solo con // y %. Muestra también la suma de las cifras, si el número es divisible entre 3 (comprobándolo de dos formas), si es par, el número al revés y si de verdad tiene 4 cifras.
Salida esperada:
--- Dígitos de 2847 --- Millares: 2 | Centenas: 8 | Decenas: 4 | Unidades: 7 Suma de dígitos: 21 ¿Divisible entre 3? True | comprobación: True ¿Es par? False Al revés: 7482 ¿Tiene 4 cifras? True
n % 10 es la última cifra y n // 10 quita la última cifra. Combinándolos: las decenas son n // 10 % 10. Un número es divisible entre 3 si la suma de sus cifras lo es.
Desafío final
Ejercicio 5: gestor de caja registradora
Una compra de 37,43 € pagada con 50 €. Calcula el cambio y desglósalo en el mínimo número de piezas: billetes de 50, 20, 10 y 5 € y monedas de 2 €, 1 €, 50, 20, 10, 5, 2 y 1 céntimo. Muestra cuántas piezas de cada tipo, el total de piezas y una comprobación de que el desglose suma exactamente el cambio. Todavía no sabemos hacer bucles, así que cada pieza va en su línea.
Salida esperada:
Cambio con floats: 12.57 --- Caja: 12,57 € de cambio --- Billetes: 50 €: 0 | 20 €: 0 | 10 €: 1 | 5 €: 0 Monedas: 2 €: 1 | 1 €: 0 | 50 cént.: 1 | 20 cént.: 0 Monedas: 10 cént.: 0 | 5 cént.: 1 | 2 cént.: 1 | 1 cént.: 0 Piezas en total: 5 ¿Cuadra el desglose? True
Pasa el cambio a céntimos con round(cambio * 100) y no vuelvas a tocar un float. Para cada pieza, divmod(resto, valor) te da cuántas caben y lo que queda, y ese resto es el que pasa a la siguiente pieza.
¿Qué falla aquí?
Tres fragmentos cortos con un error cada uno. Antes de leer la explicación, predice la salida.
Fragmento 1: el precio medio
cafe1 = 120
cafe2 = 110
cafe3 = 140
media = cafe1 + cafe2 + cafe3 / 3
print("Precio medio:", media, "céntimos")
¿Qué crees que imprime? El precio medio de tres cafés de 120, 110 y 140 céntimos debería ser 123,33.
Precio medio: 276.6666666666667 céntimos
Qué pasa: la precedencia. / va antes que +, así que Python calcula cafe3 / 3 = 46,67 y después le suma los otros dos: 120 + 110 + 46,67 = 276,67. Solo se ha dividido el último café.
Escribir la media «como se dice» (suma los tres y divide entre tres) sin paréntesis. La división solo afecta al operando que tiene pegado.
El arreglo: paréntesis alrededor de la suma.
cafe1 = 120
cafe2 = 110
cafe3 = 140
media = (cafe1 + cafe2 + cafe3) / 3 # paréntesis: primero sumar, luego dividir
print("Precio medio:", round(media, 2), "céntimos")
Esto es lo que imprime:
Precio medio: 123.33 céntimos
Ahora (120 + 110 + 140) / 3 = 370 / 3 = 123,33.
Cuando escribas una media, escribe primero los paréntesis vacíos ( ) / n y rellena la suma dentro. Así no se te olvidan nunca.
Fragmento 2: el ticket de tres cafés
total = 3 * 1.10
print("Total:", total)
print("¿Son 3,30 €?", total == 3.30)
Tres cafés de 1,10 €. ¿Son 3,30 €?
Total: 3.3000000000000003 ¿Son 3,30 €? False
Qué pasa: 1,10 no se puede guardar exacto en binario, y al multiplicarlo por 3 el error se hace visible: 3.3000000000000003. Comparado con el 3.30 escrito a mano (que tampoco es exacto, pero es otro número), == da False. Es el mismo problema que el 0.1 + 0.2 de la teoría.
Comparar el resultado de una cuenta con decimales usando ==. Puede funcionar con unos datos y fallar con otros.
El arreglo: comparar con margen o, mejor todavía, trabajar en céntimos.
import math
total = 3 * 1.10
print("¿Son 3,30 €?", math.isclose(total, 3.30)) # compara con margen
total_cent = 3 * 110 # o mejor: en céntimos
print("¿Son 330 céntimos?", total_cent == 330)
Salida real:
¿Son 3,30 €? True ¿Son 330 céntimos? True
Si tu programa maneja dinero, decide desde la primera línea que todo va en céntimos (int) y conviértelo a euros solo al mostrarlo.
Fragmento 3: el or que siempre decía que sí
El de mi anécdota:
metodo = "tarjeta"
acepta = metodo == "efectivo" or "bizum"
print("¿Se acepta?", acepta)
El método es «tarjeta», que no está entre los aceptados. ¿Qué imprime?
¿Se acepta? bizum
Qué pasa: no imprime False, ni siquiera True: imprime bizum. Python no reparte el == entre los dos lados del or. Lo que hace es:
- Evalúa la izquierda:
metodo == "efectivo"→False. - Como la izquierda es falsa,
ordevuelve la derecha tal cual: el texto"bizum". - Un texto no vacío es verdadero, así que en un
ifcontaría como «aceptado». Con cualquier método.
x == a or b para preguntar «¿x es a o b?». Siempre es «verdadero» en cuanto b no es vacío ni cero. Hay que escribir la comparación completa en los dos lados.
El arreglo:
metodo = "tarjeta"
acepta = metodo == "efectivo" or metodo == "bizum" # comparar en los dos lados
print("¿Se acepta?", acepta)
Y el resultado:
¿Se acepta? False
Y con metodo = "bizum", para comprobar que lo aceptado sigue funcionando:
¿Se acepta? True
Cuando haya muchas opciones, metodo in ("efectivo", "bizum", "tarjeta") es más corto y no tiene trampa. in pregunta si un valor está dentro de una colección; lo verás a fondo con las listas y tuplas.
Soluciones comentadas
Solución ejercicio 1
# Nivel 1 · Factura del gimnasio (todo en céntimos)
CUOTA_CENT = 2999 # 29,99 € al mes
DESCUENTO_PCT = 10 # a partir del mes 13
MESES_SIN_DESCUENTO = 12
meses = 15 # meses que lleva el socio (antes: input)
# Tramos: los 12 primeros a precio completo y el resto con descuento
meses_con_descuento = max(0, meses - MESES_SIN_DESCUENTO) # max evita negativos
meses_sin = meses - meses_con_descuento
descuento_cent = round(CUOTA_CENT * DESCUENTO_PCT / 100) # 299.9 → 300
cuota_rebajada = CUOTA_CENT - descuento_cent
# True vale 1 y False vale 0: si no hay descuento, se resta 0
tiene_descuento = meses > MESES_SIN_DESCUENTO
cuota_mes = CUOTA_CENT - descuento_cent * tiene_descuento
total = meses_sin * CUOTA_CENT + meses_con_descuento * cuota_rebajada
ahorro = meses_con_descuento * descuento_cent
print("--- Factura del gimnasio ---")
print("Meses como socio:", meses)
print(f"Cuota base: {CUOTA_CENT // 100},{CUOTA_CENT % 100:02d} €")
print(f"Cuota este mes: {cuota_mes // 100},{cuota_mes % 100:02d} €")
print(f"Total pagado: {total // 100},{total % 100:02d} €")
print(f"Ahorro acumulado: {ahorro // 100},{ahorro % 100:02d} €")
Al ejecutarlo:
--- Factura del gimnasio --- Meses como socio: 15 Cuota base: 29,99 € Cuota este mes: 26,99 € Total pagado: 440,85 € Ahorro acumulado: 9,00 €
Por qué está hecho así:
- Céntimos desde el principio: 29,99 € son 2999 céntimos. El descuento del 10 % es 299,9 céntimos, que
rounddeja en 300 (redondeo al céntimo más cercano; con//saldría 299 y el gimnasio te cobraría un céntimo de más cada mes). - Los tramos sin
if:max(0, meses - 12)da 3 con 15 meses y 0 con 8 (porque 8 − 12 = −4 ymaxse queda con el 0). Asímeses_sines 15 − 3 = 12. - El truco del
bool:tiene_descuentoesTruecon 15 meses. Multiplicado,Truevale 1:2999 - 300 * True= 2699. Con 8 meses sería2999 - 300 * False= 2999.
Las cuentas: total = 12 × 2999 + 3 × 2699 = 35988 + 8097 = 44085 céntimos (440,85 €); ahorro = 3 × 300 = 900 céntimos (9,00 €). La versión antigua de este ejercicio daba 434,85 €: estaba mal. Por eso aquí todas las salidas son de una ejecución real.
Con meses = 8, sin descuento:
--- Factura del gimnasio --- Meses como socio: 8 Cuota base: 29,99 € Cuota este mes: 29,99 € Total pagado: 239,92 € Ahorro acumulado: 0,00 €
8 × 2999 = 23992 céntimos, 239,92 €, y ahorro 0,00 €: el :02d es el que hace que salgan los dos ceros.
Calcular meses - 12 sin max. Con menos de 12 meses salen «meses con descuento» negativos y el total baja de golpe.
Solución ejercicio 2
# Nivel 1 · Conversor de tiempo: segundos → horas, minutos y segundos
segundos = 3723
horas = segundos // 3600 # horas completas
minutos = segundos % 3600 // 60 # (lo que sobra de las horas) // 60
segs = segundos % 60 # lo que no llega a un minuto
print(segundos, "segundos son:")
print("→", horas, "h,", minutos, "min y", segs, "s")
print(f"→ en formato reloj: {horas:02d}:{minutos:02d}:{segs:02d}")
# Comprobación a la inversa y la versión con divmod
print("Comprobación:", horas * 3600 + minutos * 60 + segs)
h, resto = divmod(segundos, 3600)
m, s = divmod(resto, 60)
print("Con divmod:", h, m, s)
Esto es lo que imprime:
3723 segundos son: → 1 h, 2 min y 3 s → en formato reloj: 01:02:03 Comprobación: 3723 Con divmod: 1 2 3
Por qué está hecho así:
segundos % 3600 // 60no lleva paréntesis porque%y//están en el mismo escalón y se hacen de izquierda a derecha: primero 3723 % 3600 = 123 (lo que sobra de la hora) y luego 123 // 60 = 2 minutos.segundos % 60= 3 da directamente los segundos sueltos: da igual cuántas horas haya, el resto entre 60 es lo que no llega a un minuto.:02drellena con ceros para el formato reloj.- La comprobación a la inversa: 1 × 3600 + 2 × 60 + 3 = 3723.
- La versión con
divmodhace lo mismo en dos pasos y se lee casi como una frase: «divide entre 3600 y quédate con el resto; divide el resto entre 60».
| Paso | Operación | Resultado |
|---|---|---|
| Horas | 3723 // 3600 | 1 |
| Resto tras las horas | 3723 % 3600 | 123 |
| Minutos | 123 // 60 | 2 |
| Segundos | 3723 % 60 | 3 |
Con un dato más grande, segundos = 45296:
45296 segundos son: → 12 h, 34 min y 56 s → en formato reloj: 12:34:56 Comprobación: 45296 Con divmod: 12 34 56
45296 // 3600 = 12 (12 × 3600 = 43200); sobran 2096; 2096 // 60 = 34 (34 × 60 = 2040); y 45296 % 60 = 56.
Calcular los minutos como segundos // 60 a secas: con 3723 da 62, que son los minutos totales, no los que sobran después de quitar la hora.
Solución ejercicio 3
# Nivel 2 · Análisis de una nota sobre 100, sin if: solo operadores
nota = 73
sobre_10 = nota / 10
en_rango = 0 <= nota <= 100 # comparación encadenada
aprobado = nota >= 50
notable = nota >= 70
sobresaliente = nota >= 90
# and/or devuelven un operando: el primer tramo que se cumpla «gana»
siguiente = (nota < 50 and "Aprobado") or (nota < 70 and "Notable") \
or (nota < 90 and "Sobresaliente") or "ninguno, ya es la máxima"
faltan = (nota < 50 and 50 - nota) or (nota < 70 and 70 - nota) \
or (nota < 90 and 90 - nota) or 0
sobre_aprobado = max(0, nota - 50)
print("--- Análisis de la nota", nota, "---")
print("¿Nota válida?", en_rango)
print("Sobre 10:", sobre_10)
print("¿Aprobado?", aprobado, "| ¿Notable?", notable, "| ¿Sobresaliente?", sobresaliente)
print("Siguiente nivel:", siguiente, "(faltan", faltan, "puntos)")
print("Puntos sobre el aprobado:", sobre_aprobado)
Salida real:
--- Análisis de la nota 73 --- ¿Nota válida? True Sobre 10: 7.3 ¿Aprobado? True | ¿Notable? True | ¿Sobresaliente? False Siguiente nivel: Sobresaliente (faltan 17 puntos) Puntos sobre el aprobado: 23
Por qué está hecho así: lo interesante son las dos expresiones con and y or.
siguiente = (nota < 50 and "Aprobado") or (nota < 70 and "Notable") \
or (nota < 90 and "Sobresaliente") or "ninguno, ya es la máxima"
faltan = (nota < 50 and 50 - nota) or (nota < 70 and 70 - nota) \
or (nota < 90 and 90 - nota) or 0
Así se evalúa siguiente con nota = 73, de izquierda a derecha, parando en cuanto algo es verdadero:
| Trozo | Cuenta | Valor | ¿Sigue? |
|---|---|---|---|
nota < 50 and "Aprobado" | 73 < 50 es False; and se para | False | Sí, or mira el siguiente |
nota < 70 and "Notable" | 73 < 70 es False | False | Sí |
nota < 90 and "Sobresaliente" | 73 < 90 es True; and devuelve el texto | "Sobresaliente" | No: es verdadero, or se lo queda |
faltan funciona igual y llega a 90 - nota = 17. Puntos sobre el aprobado: max(0, 73 - 50) = 23. Y 0 <= nota <= 100 es la comparación encadenada que comprueba el rango.
Con nota = 42 y con nota = 95:
--- Análisis de la nota 42 --- ¿Nota válida? True Sobre 10: 4.2 ¿Aprobado? False | ¿Notable? False | ¿Sobresaliente? False Siguiente nivel: Aprobado (faltan 8 puntos) Puntos sobre el aprobado: 0
Y la segunda:
--- Análisis de la nota 95 --- ¿Nota válida? True Sobre 10: 9.5 ¿Aprobado? True | ¿Notable? True | ¿Sobresaliente? True Siguiente nivel: ninguno, ya es la máxima (faltan 0 puntos) Puntos sobre el aprobado: 45
Con 42, el primer trozo ya es verdadero: siguiente «Aprobado», faltan 50 − 42 = 8, y max(0, 42 - 50) = 0 puntos sobre el aprobado. Con 95, ningún trozo se cumple y or llega al último valor: el texto «ninguno, ya es la máxima» y 0 puntos.
Esta técnica falla si el valor que quieres devolver es «falso». Por ejemplo, si una nota estuviera justo en el límite y el cálculo diera 70 - 70 = 0, or lo saltaría porque 0 es falso. Aquí no pasa porque cada trozo solo se cumple cuando la diferencia es positiva, pero cuando tengas if (siguiente tema) usa if para esto.
Solución ejercicio 4
# Nivel 2 · Extractor de dígitos de un número de 4 cifras, sin pasarlo a texto
n = 2847
unidades = n % 10 # la última cifra
decenas = n // 10 % 10 # quitar la última y quedarse con la nueva última
centenas = n // 100 % 10
millares = n // 1000 # con 4 cifras, lo que queda delante
suma = millares + centenas + decenas + unidades
al_reves = unidades * 1000 + decenas * 100 + centenas * 10 + millares
print("--- Dígitos de", n, "---")
print("Millares:", millares, "| Centenas:", centenas, "| Decenas:", decenas, "| Unidades:", unidades)
print("Suma de dígitos:", suma)
print("¿Divisible entre 3?", suma % 3 == 0, "| comprobación:", n % 3 == 0)
print("¿Es par?", unidades % 2 == 0)
print("Al revés:", al_reves)
print("¿Tiene 4 cifras?", 1000 <= n <= 9999)
Y el resultado:
--- Dígitos de 2847 --- Millares: 2 | Centenas: 8 | Decenas: 4 | Unidades: 7 Suma de dígitos: 21 ¿Divisible entre 3? True | comprobación: True ¿Es par? False Al revés: 7482 ¿Tiene 4 cifras? True
Por qué está hecho así: cada cifra sale de «quitar las de la derecha» con // y «quedarse con la última» con % 10.
| Cifra | Expresión | Cuenta | Resultado |
|---|---|---|---|
| Unidades | n % 10 | 2847 % 10 | 7 |
| Decenas | n // 10 % 10 | 284 % 10 | 4 |
| Centenas | n // 100 % 10 | 28 % 10 | 8 |
| Millares | n // 1000 | 2847 // 1000 | 2 |
n // 10 % 10 no necesita paréntesis por la misma razón que en el ejercicio 2: mismo escalón, de izquierda a derecha. La suma es 2 + 8 + 4 + 7 = 21, y 21 % 3 = 0, así que 2847 es divisible entre 3 (2847 = 3 × 949, y n % 3 == 0 lo confirma). El número al revés se construye multiplicando cada cifra por su nueva posición: 7 × 1000 + 4 × 100 + 8 × 10 + 2 = 7482. Y 1000 <= n <= 9999 comprueba que de verdad tiene 4 cifras.
Sacar los millares con n // 1000 % 10 está bien, pero si el número tuviera 5 cifras (12847) n // 1000 daría 12. Por eso la última línea comprueba el rango.
Solución ejercicio 5
# Nivel 3 · Caja registradora: el cambio, billete a billete y moneda a moneda
importe = 37.43
entregado = 50.00
cambio = entregado - importe
print("Cambio con floats:", cambio) # el float no es exacto
resto = round(cambio * 100) # pasamos a céntimos ENTEROS
total_cent = resto # lo guardamos para comprobar al final
# divmod(resto, valor) devuelve (cuántas piezas caben, lo que sobra)
b50, resto = divmod(resto, 5000)
b20, resto = divmod(resto, 2000)
b10, resto = divmod(resto, 1000)
b5, resto = divmod(resto, 500)
m200, resto = divmod(resto, 200)
m100, resto = divmod(resto, 100)
m50, resto = divmod(resto, 50)
m20, resto = divmod(resto, 20)
m10, resto = divmod(resto, 10)
m5, resto = divmod(resto, 5)
m2, resto = divmod(resto, 2)
m1 = resto # lo último que queda son céntimos sueltos
print(f"--- Caja: {total_cent // 100},{total_cent % 100:02d} € de cambio ---")
print("Billetes: 50 €:", b50, "| 20 €:", b20, "| 10 €:", b10, "| 5 €:", b5)
print("Monedas: 2 €:", m200, "| 1 €:", m100, "| 50 cént.:", m50, "| 20 cént.:", m20)
print("Monedas: 10 cént.:", m10, "| 5 cént.:", m5, "| 2 cént.:", m2, "| 1 cént.:", m1)
piezas = b50 + b20 + b10 + b5 + m200 + m100 + m50 + m20 + m10 + m5 + m2 + m1
suma = (b50 * 5000 + b20 * 2000 + b10 * 1000 + b5 * 500 + m200 * 200 + m100 * 100
+ m50 * 50 + m20 * 20 + m10 * 10 + m5 * 5 + m2 * 2 + m1)
print("Piezas en total:", piezas)
print("¿Cuadra el desglose?", suma == total_cent)
Al ejecutarlo:
Cambio con floats: 12.57 --- Caja: 12,57 € de cambio --- Billetes: 50 €: 0 | 20 €: 0 | 10 €: 1 | 5 €: 0 Monedas: 2 €: 1 | 1 €: 0 | 50 cént.: 1 | 20 cént.: 0 Monedas: 10 cént.: 0 | 5 cént.: 1 | 2 cént.: 1 | 1 cént.: 0 Piezas en total: 5 ¿Cuadra el desglose? True
Por qué está hecho así:
- Un solo paso con decimales:
entregado - importees la única cuenta confloat, y justo después se pasa a céntimos conround(cambio * 100). Aquí la resta se imprime como12.57, pero no siempre tendrás esa suerte (prueba conimporte = 0.10yentregado = 0.30):roundgarantiza un entero correcto pase lo que pase. Conint(cambio * 100)podrías quedarte un céntimo corto si elfloatfuera 1256,9999… divmoden cascada: cada líneapieza, resto = divmod(resto, valor)guarda cuántas piezas caben y sobrescriberestocon lo que queda, que es lo que recibe la línea siguiente. Es una asignación doble:divmoddevuelve una pareja y Python reparte sus dos valores en las dos variables.- De mayor a menor: así se consigue el mínimo de piezas (con euros funciona siempre).
Así se va comiendo el cambio, pieza a pieza:
| Pieza | divmod | Caben | Resto |
|---|---|---|---|
| 10 € | divmod(1257, 1000) | 1 | 257 |
| 5 € | divmod(257, 500) | 0 | 257 |
| 2 € | divmod(257, 200) | 1 | 57 |
| 1 € | divmod(57, 100) | 0 | 57 |
| 50 cént. | divmod(57, 50) | 1 | 7 |
| 20 y 10 cént. | divmod(7, 20), divmod(7, 10) | 0 | 7 |
| 5 cént. | divmod(7, 5) | 1 | 2 |
| 2 cént. | divmod(2, 2) | 1 | 0 |
(50 € y 20 € dan 0 con resto 1257 porque no caben.) Total: 5 piezas, y la comprobación 1000 + 200 + 50 + 5 + 2 = 1257 da True.
Hacer el desglose con float (cambio // 0.05). Con decimales, // puede dar una pieza de menos por un error minúsculo y dejar un resto de 0,0499999. En céntimos enteros nunca pasa.
Cuestionario tipo examen
Ahora ponte a prueba como en el examen. Los cuestionarios de FP1 son así: 15 preguntas en 20 minutos (16 en 30 en el de Secuencias), casi todas de respuesta única (cada fallo resta un tercio de lo que vale la pregunta) y muchas de «¿qué imprime este código?», con algún hueco, relacionar o verdadero o falso. Aquí tienes 13 preguntas originales sobre operadores. Contesta sin ejecutar nada, pulsa Comprobar y lee la explicación de cada una. Estas preguntas son también el banco del simulacro de teoría de FP1, que las mezclará con las de los demás temas.
¿Qué imprime este programa? Escribe la salida exacta.
print(17 // 5, 17 % 5)
Solución
Respuesta: 3 2
// da el cociente entero y % el resto: 17 = 5 × 3 + 2. Es la pareja que usarás para pasar segundos a minutos, sacar cifras de un número o saber si es par.
¿Qué valor muestra este código?
a = True b = False print(not a or b and a)
FalseTrue- Un error de sintaxis
None
Solución
Respuesta: False
Prioridad de mayor a menor: not, and, or. Se calcula como (not a) or (b and a) = False or False = False. Si dudas, pon paréntesis: nadie te va a quitar puntos por usarlos.
¿Qué imprime este programa? Escribe la salida exacta.
print(2 + 3 * 4 ** 2)
Solución
Respuesta: 50
Primero la potencia: 4 ** 2 = 16. Después la multiplicación: 3 × 16 = 48. Y al final la suma: 2 + 48 = 50.
¿Cuál de estas expresiones es True cuando n es par?
n % 2 == 0n / 2 == 0n // 2 == 1n % 2 == 1
Solución
Respuesta: n % 2 == 0
% es el operador estrella para preguntar «¿es múltiplo de…?». n % 2 == 0 → par; n % 3 == 0 → múltiplo de 3.
Relaciona cada expresión con su resultado:
7 / 2 | |
7 // 2 | |
7 % 2 | |
2 ** 3 |
Definiciones:
- 1
- 6
- 14
- 3.5
- 3
- 8
Solución
7 / 2→ 3.57 // 2→ 37 % 2→ 12 ** 3→ 8
/ es división con decimales, // cociente entero, % resto y ** potencia. 2 ** 3 = 2 × 2 × 2 = 8 (no 6: no es una multiplicación).
Un compañero quiere comprobar si color es 'rojo' o 'azul' y escribe color == 'rojo' or 'azul'. ¿Qué pasa?
- La condición es siempre verdadera, porque
'azul'sola cuenta comoTrue - Funciona bien
- Da un error de sintaxis
- Es siempre falsa
Solución
Respuesta: La condición es siempre verdadera, porque 'azul' sola cuenta como True
Python lee (color == 'rojo') or ('azul'). Si la primera parte es falsa, el or devuelve 'azul', y un texto no vacío es «verdadero» en un if. Es uno de los fallos más típicos de FP1.
¿Qué imprime este programa? Escribe la salida exacta.
total = 10 total += 5 total *= 2 total -= 4 print(total)
Solución
Respuesta: 26
+=, *= y -= son abreviaturas: 10 + 5 = 15, 15 × 2 = 30, 30 − 4 = 26.
Indica si es verdadero o falso:
5 == 5.0esTrue.'5' == 5esTrue.3 < 5 < 9esTrue.=y==hacen lo mismo.
Solución
- V —
5 == 5.0esTrue. - F —
'5' == 5esTrue. - V —
3 < 5 < 9esTrue. - F —
=y==hacen lo mismo.
Un int y un float con el mismo valor son iguales, pero un texto nunca es igual a un número. Python permite encadenar comparaciones (3 < 5 < 9 es 3 < 5 and 5 < 9). Y = asigna, mientras que == compara.
¿Qué valor da round(2.5) en Python?
232.5- Un error
Solución
Respuesta: 2
Con los empates (x,5), round va al par: round(2.5) es 2 y round(3.5) es 4. Es una trampa que cae en más de un cuestionario.
¿Qué imprime este código?
x = 0 print(x != 0 and 10 / x > 1)
False- Un error
ZeroDivisionError True0
Solución
Respuesta: False
and y or evalúan en cortocircuito: si la primera parte del and es falsa, ya saben el resultado y no miran la segunda. Así se protege una división: «comprueba antes de dividir».
Completa para pasar 135 segundos a minutos y segundos (2 min 15 s):
minutos = 135 ____ 60 y segundos = 135 ____ 60
Palabras:
- %
- //
- **
- /
Solución
minutos = 135 // 60 y segundos = 135 % 60
135 // 60 = 2 minutos y 135 % 60 = 15 segundos. Con / saldría 2.25, que no son minutos y segundos.
¿Qué imprime este programa?
print("ja" * 3 + "!")jajaja!ja3!- Un error
ja ja ja !
Solución
Respuesta: jajaja!
Con textos, + concatena y * n repite n veces. La multiplicación va antes: 'ja' * 3 = 'jajaja', y después se le une el '!'.
¿Qué valor tiene -7 // 2?
-4-3-3.53
Solución
Respuesta: -4
-7 / 2 = -3.5, y // va al entero de abajo: -4. Con positivos parece que «quita decimales», pero con negativos se nota la diferencia.
Míralo paso a paso en Python Tutor
Vamos a ver en directo el or del fragmento 3. Copia esto en Python Tutor, elige Python 3 y avanza línea a línea:
metodo = "tarjeta" # Versión con el fallo: or devuelve "bizum", que es verdadero mal = metodo == "efectivo" or "bizum" # Lo que Python hace por dentro, paso a paso izquierda = metodo == "efectivo" # False mal_2 = izquierda or "bizum" # False or "bizum" → "bizum" # Versión correcta: una comparación completa a cada lado bien = metodo == "efectivo" or metodo == "bizum" print(mal, mal_2, bien)
Salida:
bizum bizum False
Qué observar paso a paso:
- Tras la línea de
mal, la variable aparece con el valor"bizum": unstr, no unbool. Ese es el síntoma. izquierdavaleFalse: la comparación con «efectivo» sí se hace, y es falsa.mal_2repite la cuenta en dos pasos y vuelve a dar"bizum":False or "bizum"devuelve el segundo operando.bienvaleFalse, unboolde verdad: con la comparación completa en los dos lados, «tarjeta» no se acepta.- Cambia
metodoa"bizum"y vuelve a ejecutar:bienpasa aTrueymalsigue valiendo"bizum". Con cualquier método,malsería igual.
Chuletario: operadores en Python
Lo esencial en 30 segundos: / siempre da float; // es el cociente redondeado hacia abajo y % el resto (y b * (a // b) + a % b == a). Las comparaciones dan bool; != es «distinto de». and y or se paran en cuanto saben la respuesta y devuelven uno de sus operandos. Los decimales no se comparan con ==: céntimos o math.isclose. En caso de duda, paréntesis.
| Quiero… | Código | Resultado |
|---|---|---|
| Dividir con decimales | 7 / 2 | 3.5 |
| Cuántos grupos caben | 17 // 5 | 3 |
| Lo que sobra | 17 % 5 | 2 |
| Las dos cosas | divmod(17, 5) | (3, 2) |
| Potencia y raíz | 2 ** 10, 9 ** 0.5 | 1024, 3.0 |
| Par o impar | n % 2 == 0 | True si es par |
| Última cifra | 2847 % 10 | 7 |
| Quitar la última cifra | 2847 // 10 | 284 |
| Céntimos a euros | f"{c // 100},{c % 100:02d} €" | 10,91 € con 1091 |
| Segundos a h, min, s | s // 3600, s % 3600 // 60, s % 60 | 1 2 3 con 3723 |
| Distinto de | precio != 100 | True |
| Dentro de un rango | 0 <= nota <= 100 | True |
| Comparar decimales | math.isclose(0.1 + 0.2, 0.3) | True |
| Valor por defecto | nombre or "Anónimo" | 'Anónimo' si nombre es "" |
| Proteger una división | b != 0 and a / b > 3 | sin ZeroDivisionError |
| Varias opciones | metodo in ("efectivo", "bizum") | True o False |
Precedencia (de más a menos): () → ** → signo -x → * / // % → + - → comparaciones → not → and → or. ** se agrupa de derecha a izquierda (2 ** 3 ** 2 = 512); el resto, de izquierda a derecha.
Plantillas de los ejercicios:
| Ejercicio | Plantilla | Con los datos de hoy |
|---|---|---|
Tramos sin if | max(0, meses - 12) | 3 meses con descuento |
| Bool como número | cuota - descuento * tiene_descuento | 2699 |
| Tiempo | h, r = divmod(s, 3600); m, s = divmod(r, 60) | 1, 2, 3 |
| Siguiente nivel | (n < 70 and "Notable") or (n < 90 and "Sobresaliente") or "…" | 'Sobresaliente' |
| Cifras | n // 10 ** k % 10 | cifra en la posición k |
| Cambio | piezas, resto = divmod(resto, valor) en cascada | 5 piezas para 1257 |
| Síntoma | Causa probable |
|---|---|
Sale 5.0 en lugar de 5 | Has usado /; si quieres un entero, // |
-7 // 2 da −4 y esperabas −3 | // redondea hacia abajo; para cortar, int(-7 / 2) |
0.1 + 0.2 == 0.3 da False | Decimales en binario; usa math.isclose o céntimos |
| La media sale enorme | Falta el paréntesis: (a + b + c) / 3 |
-2 ** 2 da −4 | ** va antes que el signo; escribe (-2) ** 2 |
Un or acepta cualquier cosa | x == a or b; escribe x == a or x == b |
ZeroDivisionError con un and | La división va antes que la comprobación; cambia el orden |
NameError con += | La variable no estaba inicializada (total = 0) |
Antes de entregar, pregúntate:
- ¿Cada división es la que toca (
/para decimales,//para «cuántos caben»)? - ¿Hay algún
==entre dosfloat? Si lo hay, ¿puedes usar céntimos omath.isclose? - ¿Las fórmulas con suma y multiplicación llevan los paréntesis que harías a mano?
- ¿Cada
ory cadaandtiene una comparación completa a los dos lados?
Y con esto tienes los operadores dominados. El siguiente paso son los condicionales en Python: verás cómo if, elif y else convierten estas comparaciones en decisiones, y cómo el ejercicio 3 queda mucho más legible. Si quieres repasar de dónde venimos, aquí tienes variables y tipos de datos en Python.
¿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)