Variables y tipos de datos en Python — práctica con tu nota media, el IMC y el precio de la matrícula (y unos céntimos que salen de la nada)
En la primera práctica de FP1 hice el clásico calculador del IMC. Lo ejecuté, metí mis datos y el programa me dijo, muy serio: Tu IMC es: 0.0. Ni error, ni aviso, nada. Estuve un buen rato revisando la fórmula hasta que el profesor se asomó a mi pantalla y me preguntó: «¿en qué unidades has escrito la altura?». En centímetros. Python había hecho la cuenta perfectamente… con un dato que no significaba lo que yo creía. Esa es la lección de esta práctica: un programa sin errores no es un programa correcto; hay que saber qué tipo y qué significado tiene cada dato que entra.
En la teoría de variables y tipos de datos viste qué es una variable, los tipos int, float, str y bool y cómo convertir entre ellos. Aquí lo usamos en tres programas completos, todos de nivel de primera semana pero con datos que se parecen a los de verdad: notas con decimales, una altura que llega como texto (y a veces con coma o en centímetros) y un precio que, al dividirlo en plazos, se inventa unos céntimos. Seguimos con el ejemplo de tu ficha de estudiante: tu nota media, tu IMC y lo que te cuesta la matrícula.
Tabla de Contenidos
Antes de empezar
Conviene tener claro:
- Que
input()siempre devuelve unstr, y que se convierte conint()ofloat(). - La diferencia entre
int(se cuenta) yfloat(se mide o lleva decimales). - Que
type()te dice el tipo de cualquier valor. - Que
round(x, 2)redondea a dos decimales yf"{x:.2f}"lo escribe con dos decimales.
Si alguno te suena dudoso, repasa la teoría antes de seguir.
En clase leerías los datos con input(). Aquí los escribimos ya como texto (nota1_txt = "7") para que las salidas sean siempre las mismas y puedas compararlas con las tuyas. Es exactamente lo que te devolvería input() si tecleases esos valores. Para leerlos de verdad, cambia cada línea por nota1_txt = input("Nota 1: ") y el resto del programa no cambia. Si aún no tienes Python, empieza por instalar Python en Windows. Crea una carpeta practica_variables en VS Code (aquí tienes cómo configurarlo) y un archivo por programa.
Programa 1: Calculadora de nota media
El programa recibe tus tres notas de una asignatura como texto, calcula la media, la redondea a dos decimales y dice si estás aprobado. Lo que lo complica no es la cuenta: es que los datos llegan como str, que una nota puede llevar decimales ("8.5") y que la media de 7, 8.5 y 6 no es un número «bonito».
La idea
Cuatro pasos, siempre en este orden: convertir → calcular → redondear → decidir.
- Convertir cada texto a
float(no aint, porqueint("8.5")explota). - Sumar las tres notas y después dividir entre 3.
- Redondear solo el resultado final, para enseñarlo.
- Guardar en un
boolla respuesta a «¿la media es al menos 5?».
Antes de programar, piensa en qué tipo tiene cada dato en cada paso. Si sabes que nota1_txt es str, nota1 es float y aprobado es bool, ya tienes medio programa escrito.
El código
# Programa 1 · Calculadora de nota media
# Las notas llegan como TEXTO, igual que si las hubieras leído con input()
nota1_txt = "7"
nota2_txt = "8.5"
nota3_txt = "6"
# 1) Convertir: float y no int, porque una nota puede llevar decimales ("8.5")
nota1 = float(nota1_txt)
nota2 = float(nota2_txt)
nota3 = float(nota3_txt)
# 2) Calcular: el paréntesis hace que se sume TODO antes de dividir
media = (nota1 + nota2 + nota3) / 3
print("Media sin redondear:", media)
# 3) Redondear a 2 decimales solo al final, para enseñar el resultado
media_redondeada = round(media, 2)
# 4) Un bool guarda la respuesta a "¿he aprobado?"
aprobado = media_redondeada >= 5.0
print(f"Tu nota media es: {media_redondeada}")
print(f"¿Aprobado?: {aprobado}")
print(type(nota1_txt), type(nota1), type(aprobado))
Salida
Media sin redondear: 7.166666666666667 Tu nota media es: 7.17 ¿Aprobado?: True <class 'str'> <class 'float'> <class 'bool'>
Comprobación a mano: 7 + 8,5 + 6 = 21,5, y 21,5 / 3 = 7,1666… (el 6 se repite para siempre). Python guarda los decimales que le caben, 7.166666666666667 (el último 7 es el redondeo interno). round(…, 2) lo deja en 7,17, que es ≥ 5, así que aprobado vale True. La última línea confirma los tipos: el dato de entrada era str, la nota convertida es float y la respuesta es bool.
El corazón del programa son estas tres líneas:
# 2) Calcular: el paréntesis hace que se sume TODO antes de dividir
media = (nota1 + nota2 + nota3) / 3
print("Media sin redondear:", media)
El paréntesis no es decoración. En Python, como en matemáticas, la división se hace antes que la suma; sin paréntesis, nota1 + nota2 + nota3 / 3 calcularía 7 + 8,5 + 2 = 17,5. El dibujo resume el viaje de los datos, con el tipo de cada paso:
Preguntas que te puedes hacer
¿Por qué float() y no int()? Porque una nota puede ser "8.5", e int("8.5") da ValueError. Aunque hoy tus notas sean enteras, el programa tiene que aguantar la que no lo sea. float("7") funciona sin problema y da 7.0.
¿Por qué no redondeo cada nota antes de sumar? Porque cada redondeo pierde un poco de información, y si redondeas antes, el error se acumula. La regla es: calcula con todos los decimales y redondea solo lo que enseñas.
¿round(media, 2) cambia media? No. round() crea un número nuevo; media sigue valiendo 7.166666666666667. Por eso guardamos el redondeado en otra variable, media_redondeada.
¿Qué es eso de f"…{media_redondeada}"? Una f-string: un texto con huecos entre llaves donde Python escribe el valor de la variable. Es la forma más cómoda de mezclar texto y números sin convertir nada a mano.
¿Por qué aprobado sale True y no «Sí»? Porque es un bool, el resultado de la comparación >= 5.0. Si quisieras escribir «Sí» o «No», necesitarías un if, que llega en el tema de condicionales.
Olvidar el paréntesis de la media. nota1 + nota2 + nota3 / 3 no da error: da 17.5, que es un número perfectamente válido… y perfectamente falso. Los errores de lógica son los más peligrosos porque Python no te avisa.
Pruébalo tú
- Cambia
nota2_txta"8,5"(con coma) y lee el error que da. Después arréglalo con.replace(",", ".")antes de convertir:float(nota2_txt.replace(",", ".")). - Añade una cuarta nota y fíjate en qué dos líneas tienes que tocar (la suma y el divisor). ¿Qué pasa si te olvidas de cambiar el 3 por un 4?
Programa 2: Calculador del IMC
El índice de masa corporal se calcula dividiendo el peso (en kilos) entre la altura (en metros) al cuadrado. El programa recibe tu nombre, tu peso y tu altura como texto y te enseña el IMC con un decimal. Lo que lo complica son las unidades y el formato del dato: una altura con coma o en centímetros rompe el programa de dos formas muy distintas.
La idea
El nombre ya es texto, así que se queda como está. El peso y la altura se convierten a float. Después se aplica la fórmula IMC = peso / altura², se redondea a un decimal y se enseñan los pasos intermedios para poder comprobarlos.
Antes de programar, pregúntate en qué unidades llega cada dato y qué separador decimal usa. Son las dos cosas que el usuario va a hacer «a su manera».
El código
# Programa 2 · Calculador del IMC
nombre = "Sergio" # str: ya es texto, no hay que convertirlo
peso_txt = "70" # kilos, tal como llegaría de input()
altura_txt = "1.78" # metros, con PUNTO decimal
peso = float(peso_txt)
altura = float(altura_txt)
# IMC = peso / altura². ** es la potencia y se calcula antes que la división
imc = peso / altura ** 2
imc_redondeado = round(imc, 1)
print(f"\nResultados para {nombre}:")
print(f"Altura al cuadrado: {altura ** 2}")
print(f"IMC sin redondear: {imc}")
print(f"Tu IMC es: {imc_redondeado}")
Salida
Resultados para Sergio: Altura al cuadrado: 3.1684 IMC sin redondear: 22.093170054286073 Tu IMC es: 22.1
Comprobación a mano: 1,78² = 1,78 × 1,78 = 3,1684, y 70 / 3,1684 = 22,093… que con un decimal es 22,1. El \n del principio del primer print es un salto de línea: por eso la salida empieza con una línea en blanco.
peso / altura ** 2 funciona sin paréntesis porque ** (la potencia) se calcula antes que /. Si escribieras (peso / altura) ** 2, dividirías primero y elevarías después: 39,3… al cuadrado, un IMC de más de 1.500.
Ahora, los dos errores del gancho. Si la altura llega con coma (altura_txt = "1,78"), el programa ni siquiera llega a calcular:
Traceback (most recent call last):
File "imc_coma.py", line 7, in <module>
altura = float(altura_txt)
ValueError: could not convert string to float: '1,78'
Y si llega en centímetros (altura_txt = "178"), el programa funciona… y miente:
Resultados para Sergio: Altura al cuadrado: 31684.0 IMC sin redondear: 0.0022093170054286074 Tu IMC es: 0.0
178² = 31.684 y 70 / 31.684 = 0,0022…, que redondeado a un decimal da 0,0. Es mi IMC de 0.0 del gancho: ningún error, solo un dato con otro significado. Fíjate en la diferencia: el primero es un error que Python detecta (ValueError); el segundo, uno que solo detectas tú mirando si el resultado tiene sentido.
Preguntas que te puedes hacer
¿Por qué nombre no se convierte? Porque ya es un str y lo queremos como texto. Convertir solo lo que vas a usar para calcular.
¿Por qué float también para el peso, si 70 es entero? Porque alguien pesará 70.5. Si el dato puede tener decimales, float.
¿Qué hace \n dentro del texto? Es un carácter especial, el salto de línea. Dentro de una cadena, la barra invertida \ anuncia un carácter especial: \n (salto de línea), \t (tabulador)…
¿Por qué Python no me avisa de lo de los centímetros? Porque para Python 178 es un número perfectamente válido. Los tipos protegen de algunos errores (no puedes dividir un texto), pero no de las unidades: eso es cosa del programador. Más adelante podrás comprobarlo con un if («si la altura es mayor que 3, seguramente está en centímetros»).
Escribir decimales con coma, como hacemos en español. float("1,78") da ValueError, y en el código altura = 1,78 es aún peor: no da error, pero crea la tupla (1, 78).
Imprime los pasos intermedios (aquí, altura ** 2) mientras desarrollas. Si el IMC sale raro, verás enseguida si el problema está en la altura o en la división. Cuando funcione, puedes borrar esas líneas.
Pruébalo tú
- Haz que el programa acepte la coma:
float(altura_txt.replace(",", ".")), y compruébalo con"1,78". - Cambia la altura a
"178"y conviértela a metros dividiendo entre 100 justo después de convertirla. ¿Te vuelve a salir 22.1?
Programa 3: El precio de tu matrícula
El programa calcula cuánto cuesta matricularte de 5 asignaturas de 6 créditos a 18,32 € el crédito (un precio de ejemplo) y lo divide en 3 plazos. Tiene datos de los tres tipos numéricos (el número de asignaturas es un int, los créditos llegan como texto y el precio también) y enseña el problema del dinero con float: el plazo sale con unos céntimos fantasma.
La idea
Primero decidir el tipo de cada dato: las asignaturas y los créditos se cuentan (int), el precio se mide en euros con céntimos (float). Después, tres cuentas encadenadas: créditos totales, precio total y precio por plazo. Por último, enseñar el dinero con dos decimales.
Antes de programar, escribe en un papel cada cuenta con sus tipos: int * int, int * float, float / int. Así sabrás de antemano qué tipo va a salir.
El código
# Programa 3 · El precio de tu matrícula
asignaturas = 5 # int: las asignaturas se cuentan, no se miden
creditos_txt = "6" # créditos de cada asignatura, como llegan de input()
precio_txt = "18.32" # euros por crédito (precio de ejemplo)
plazos = 3 # pagas en 3 plazos
# Convertir cada dato al tipo que le toca
creditos_asignatura = int(creditos_txt) # "6" -> 6: los créditos son enteros
precio_credito = float(precio_txt) # "18.32" -> 18.32: el dinero lleva decimales
creditos = asignaturas * creditos_asignatura # int * int = int
total = creditos * precio_credito # int * float = float
plazo = total / plazos # / siempre devuelve float
print("Créditos:", creditos, type(creditos))
print("Total:", total, type(total))
print("Cada plazo (sin redondear):", plazo)
# Para enseñar dinero: 2 decimales con round() o con el formato :.2f
print("Cada plazo (round):", round(plazo, 2))
print(f"Cada plazo (:.2f): {plazo:.2f} €")
print(f"Resumen: {creditos} créditos x {precio_credito} € = {total:.2f} €")
Salida
Créditos: 30 <class 'int'> Total: 549.6 <class 'float'> Cada plazo (sin redondear): 183.20000000000002 Cada plazo (round): 183.2 Cada plazo (:.2f): 183.20 € Resumen: 30 créditos x 18.32 € = 549.60 €
Comprobación a mano: 5 × 6 = 30 créditos; 30 × 18,32 = 549,60 €; 549,60 / 3 = 183,20 € por plazo. Python acierta en las dos primeras, pero en la tercera escribe 183.20000000000002: es el sobrante del binario que viste en la teoría. round(plazo, 2) lo arregla como número (183.2, sin el cero final) y :.2f como texto (183.20 €, con los dos decimales, como en cualquier recibo).
Las tres cuentas, con zoom:
creditos = asignaturas * creditos_asignatura # int * int = int total = creditos * precio_credito # int * float = float plazo = total / plazos # / siempre devuelve float
La regla que deciden los tipos es sencilla: int con int da int (salvo con /), basta un float en la cuenta para que el resultado sea float, y / siempre da float, aunque la división sea exacta. Lo ves en la salida (<class 'int'> y <class 'float'>) y en el dibujo:
Una tabla de traza con el valor y el tipo de cada variable después de cada línea:
| Línea | Variable | Valor | Tipo |
|---|---|---|---|
| 8 | creditos_asignatura | 6 | int |
| 9 | precio_credito | 18.32 | float |
| 11 | creditos | 30 | int |
| 12 | total | 549.6 | float |
| 13 | plazo | 183.20000000000002 | float |
| 21 | (texto del print) | "Cada plazo (:.2f): 183.20 €" | str |
Preguntas que te puedes hacer
¿Por qué asignaturas = 5 no lleva comillas y creditos_txt = "6" sí? Para practicar los dos casos: un dato que ya escribes tú como número y otro que llega de fuera como texto. En un programa real, todo lo que venga de input() llegará como el segundo.
¿Por qué int() para los créditos y no float()? Porque los créditos se cuentan: no existe una asignatura de 6,5 créditos en el plan. Usar int deja claro qué significa el dato y, si alguien escribe "6.5", el ValueError te avisa de que algo no cuadra.
¿Es un fallo de Python lo de 183.20000000000002? No. Es cómo funcionan los float en todos los lenguajes (también en Java o en C). Los programas de bancos trabajan en céntimos con enteros o con el módulo decimal precisamente por esto.
¿Qué diferencia hay entre round(plazo, 2) y f"{plazo:.2f}"? round devuelve un número (puedes seguir calculando con él) y no añade ceros: 183.2. :.2f produce un texto con exactamente dos decimales: 183.20. Para cuentas, round; para enseñar dinero, :.2f.
Redondear con :.2f y después intentar operar con el resultado. f"{plazo:.2f}" es un str: si haces f"{plazo:.2f}" * 3 obtienes el texto repetido tres veces, no 549,60.
El precio de 18,32 € por crédito es un ejemplo para que la cuenta sea fácil de seguir. Cada universidad y cada comunidad autónoma fija el suyo, y cambia de un curso a otro.
Pruébalo tú
- Añade unas tasas fijas de secretaría (un
float, por ejemplo"27.50") al total antes de dividir en plazos, y comprueba a mano el resultado. - Calcula cuánto pagarías si te matricularas de 8 asignaturas en lugar de 5. ¿Qué variable tienes que cambiar y cuántas cuentas se recalculan solas?
Errores típicos en esta práctica
- Convertir con
int()un dato que puede llevar decimales.int("8.5")daValueError. Notas, pesos, alturas y precios van confloat(). - Olvidar convertir.
"7" + "8.5"da"78.5": el programa sigue adelante con un texto que parece un número. - Olvidar los paréntesis de la media.
a + b + c / 3divide solo la última nota. - Escribir los decimales con coma. En el código crea una tupla; en
float()daValueError. - Mezclar unidades. Una altura en centímetros no da error, da un IMC de 0.0. Comprueba que el resultado tiene sentido.
- Enseñar dinero sin formato.
183.20000000000002 €en un recibo queda fatal: usa:.2f.
Míralo paso a paso en Python Tutor
Abre Python Tutor, elige Python 3 y pega esta versión corta del programa 1:
nota1_txt = "7" # texto, como si viniera de input() nota2_txt = "8.5" nota3_txt = "6" nota1 = float(nota1_txt) nota2 = float(nota2_txt) nota3 = float(nota3_txt) suma = nota1 + nota2 + nota3 media = suma / 3 media_redondeada = round(media, 2) aprobado = media_redondeada >= 5.0 print(media_redondeada, aprobado)
Su salida:
7.17 True
Qué observar, avanzando con Next:
- Tras las tres primeras líneas, las variables
nota1_txt,nota2_txtynota3_txtaparecen con comillas:"7","8.5","6". Son textos. - Tras las conversiones,
nota1vale7.0(con punto: es unfloat), aunque el texto era"7". Ynota1_txtsigue ahí, intacta: convertir crea un objeto nuevo, no cambia el original. - Al calcular
suma, vale21.5; ymedia,7.166666666666667. Compara con tu cuenta a mano. - Al calcular
media_redondeada,mediano cambia. Las dos conviven: una para calcular y otra para enseñar. - Al final,
aprobadoaparece comoTrue, sin comillas: es unbool, no el texto"True".
Resumen
- Todo lo que llega de fuera (como lo que devuelve
input()) es texto: conviértelo nada más recibirlo. intpara lo que se cuenta yfloatpara lo que se mide o lleva decimales.- Calcula con todos los decimales y redondea solo al final, para enseñar.
intconintdaint, unfloaten la cuenta la vuelvefloat, y/siempre dafloat.round()devuelve un número;:.2fdevuelve un texto con dos decimales.- Un programa sin errores puede estar mal: comprueba las unidades y haz la cuenta a mano.
Checklist: ¿lo has practicado?
- ¿Has ejecutado los tres programas y comprobado las salidas?
- ¿Sabrías decir el tipo de cada variable de la matrícula sin mirar la tabla?
- ¿Has provocado tú mismo el
ValueErrorde"1,78"y lo has arreglado? - ¿Entiendes por qué la altura en centímetros no da error?
- ¿Sabes cuándo usar
round()y cuándo:.2f? - ¿Has intentado los «Pruébalo tú» sin mirar la teoría?
Si has respondido que sí a casi todo, estás listo para los ejercicios de variables y tipos de datos, donde ya no te doy el código hecho. ¡Nos vemos allí! Y después, el siguiente tema: operadores en Python.
Siguiente paso: ejerciciosVariables y tipos de datos en Python — ejercicios con un recibo, temperaturas, propinas y tu ficha de estudiante (y un True que vale 1)¿Te ha servido este artículo? Así puedes apoyar SergioLearns →




El hardware que sostiene al sistema operativo — teoría con la práctica de IC2 en la impresora, una interrupción que lo para todo y una caché que acierta (y el bucle infinito que no colgó mi portátil)