Variables y tipos de datos en Python — teoría con tu ficha de estudiante, etiquetas que apuntan a objetos y el «5» que no era un 5 (y la nota media que me salió 78.5)

Primera semana de FP1. Nos piden un programa que lea dos notas con input() y calcule la media. Fácil, ¿no? Escribo las dos notas, sumo, divido entre 2… y el programa me enseña esto antes de morir:

# Mi primera "nota media" en FP1 (la versión con el fallo)
# input() siempre devuelve texto: aquí escribo lo que me devolvió
nota1 = "7"      # lo que devuelve input() si tecleas 7
nota2 = "8.5"    # lo que devuelve input() si tecleas 8.5

suma = nota1 + nota2     # con textos, + pega en vez de sumar
print("Suma de las notas:", suma)
media = suma / 2         # dividir un texto entre 2: aquí explota
print("Media:", media)
Suma de las notas: 78.5
Traceback (most recent call last):
  File "gancho.py", line 8, in <module>
    media = suma / 2         # dividir un texto entre 2: aquí explota
            ~~~~~^~~
TypeError: unsupported operand type(s) for /: 'str' and 'int'

Fíjate en la primera línea de la salida: 78.5. Parece un número. Parece hasta una suma razonable si no miras mucho. Pero no es la suma de 7 y 8.5 (que sería 15.5): es el texto "7" pegado al texto "8.5". Y cuando intento dividir ese texto entre 2, Python se planta con un TypeError. Esa tarde aprendí que en Python no basta con saber qué valor tiene una variable: hay que saber de qué tipo es.

En este artículo vas a ver qué es de verdad una variable (spoiler: una etiqueta, no una caja), los cuatro tipos de datos que vas a usar siempre (int, float, str y bool), cómo convertir de uno a otro y los tres errores que te vas a encontrar sí o sí: el de input(), el del "5" que no es un 5 y el de los decimales que no cuadran. Si todavía no tienes Python instalado, empieza por cómo instalar Python en Windows. Y cuando acabes, tienes la práctica con tres programas completos.

Todo el artículo gira alrededor de un ejemplo que conoces bien: tu ficha de estudiante (nombre, edad, notas, créditos, matrícula).

¿Qué es una variable?

Una variable es un nombre que le pones a un dato para poder usarlo después. La creas la primera vez que le asignas un valor con =. No hay que «declararla» antes ni decir de qué tipo es: Python lo averigua solo mirando el valor.

# Tu ficha de estudiante en variables: nombre = valor
nombre = "Sergio"        # str: texto, siempre entre comillas
edad = 19                # int: número entero, sin comillas
nota_fp1 = 7.5           # float: número con decimales (punto, no coma)
matriculado = True       # bool: verdadero o falso, con mayúscula

print(nombre, "tiene", edad, "años")
print("Nota de FP1:", nota_fp1)
print("¿Matriculado?", matriculado)

edad = edad + 1          # primero la derecha (19 + 1), luego se guarda en edad
print("El año que viene tendrá", edad)
Sergio tiene 19 años
Nota de FP1: 7.5
¿Matriculado? True
El año que viene tendrá 20

Tres cosas que conviene tener claras desde el primer día:

  • El = no es el igual de matemáticas. Es una asignación: «calcula lo de la derecha y ponle este nombre». Por eso edad = edad + 1 tiene sentido en Python (en matemáticas sería absurdo): primero se calcula 19 + 1 = 20 con el valor que había y después el nombre edad pasa a referirse al 20.
  • Las comillas importan. "Sergio" es un texto; Sergio sin comillas sería el nombre de una variable (y como no existe, un error).
  • print() con comas separa los datos con un espacio. Por eso sale Sergio tiene 19 años sin que hayamos escrito los espacios a mano.

En Java o en C escribirías int edad = 19;, diciendo el tipo delante. Python tiene tipado dinámico: el tipo lo lleva el valor, no el nombre. Eso es justo lo que hace que empezar sea tan cómodo… y lo que provoca el error del gancho.

La variable es una etiqueta, no una caja

Mucha gente se imagina una variable como una caja con el valor dentro. En Python es más exacto pensar en etiquetas pegadas a objetos: el valor (el objeto) vive en la memoria con su tipo, y el nombre solo apunta a él. Míralo en el dibujo con los datos de la ficha:

Las variables son nombres que apuntan a objetosCuatro nombres de la ficha de estudiante (nombre, edad, nota_fp1, matriculado) con flechas hacia sus objetos: el texto Sergio de tipo str, el 19 de tipo int, el 7.5 de tipo float y True de tipo bool.Nombres (variables)Objetos en memoria: valor + tiponombre"Sergio"stredad19intnota_fp17.5floatmatriculadoTruebooltype(edad) → <class 'int'>
El nombre no guarda el tipo: lo lleva el objeto al que apunta (fíjate en la pastilla de cada caja).

Fíjate en que la pastilla de tipo (str, int, float, bool) está en la caja de la derecha, la del objeto, no en el nombre. Esa es la idea más importante del tema y la que vamos a usar en la sección de tipado dinámico.

Reglas para nombrar variables

Python es estricto con cómo se escriben los nombres, y el estilo de la asignatura (y de todo el mundo en Python, la guía PEP 8) añade unas costumbres más:

Nombre¿Vale?Por qué
nota_mediaSíMinúsculas y palabras separadas por _ (el estilo recomendado, snake_case)
_temporalSíPuede empezar por guion bajo
nota2SíPuede llevar números…
2notaNo…pero no empezar por un número
nota mediaNoNo admite espacios
nota-mediaNoEl - es la resta: Python leería nota - media
class, if, TrueNoSon palabras reservadas del lenguaje
NotaMediaSí, peroFunciona, pero ese estilo se reserva para las clases

Si te saltas una regla, el programa ni siquiera empieza: Python lo comprueba todo antes de ejecutar la primera línea y te da un SyntaxError.

nota_media = 7.17        # bien: minúsculas y guion bajo
1nota = 7                # mal: un nombre no puede empezar por un número
  File "nombre_mal.py", line 2
    1nota = 7                # mal: un nombre no puede empezar por un número
    ^
SyntaxError: invalid decimal literal

El ^ señala justo dónde se ha perdido: en el 1 del principio. Y hay otro detalle que se olvida mucho: Python distingue mayúsculas de minúsculas. nota y Nota son dos variables distintas, y usar un nombre que nunca has creado da un NameError:

nota = 7
Nota = 9                 # otra variable distinta: Python distingue mayúsculas
print(nota, Nota)
print(nota_final)        # nunca se creó: NameError
7 9
Traceback (most recent call last):
  File "mayusculas.py", line 4, in <module>
    print(nota_final)        # nunca se creó: NameError
          ^^^^^^^^^^
NameError: name 'nota_final' is not defined

Escribir Nota en una línea y nota en otra creyendo que es la misma variable. Python no avisa: simplemente crea otra. Si un valor «no se actualiza», busca primero una mayúscula traidora.

Usa nombres que digan qué guardan (nota_fp1, precio_credito) en lugar de x, a o dato2. Dentro de tres semanas, cuando releas tu práctica, me lo agradecerás.

Los tipos de datos que usarás siempre

En primero vas a trabajar casi todo el tiempo con cuatro tipos básicos, más un quinto valor especial:

TipoQué guardaEjemplosEn tu ficha
intNúmeros enteros, positivos o negativos, sin límite de tamaño19, -3, 0, 2026edad, créditos, número de asignaturas
floatNúmeros con parte decimal (se escriben con punto)7.5, 18.32, -0.5, 1.0notas, precio por crédito, altura
strTexto entre comillas simples o dobles"Sergio", 'GCID', "7"nombre, carrera, universidad
boolVerdadero o falsoTrue, False¿matriculado?, ¿aprobado?
NoneTypeLa «ausencia de valor»: solo existe NoneNoneuna nota que todavía no se ha puesto

Para saber qué tipo tiene un objeto, se lo preguntas a Python con type():

# type() te dice el tipo del objeto al que apunta cada nombre
nombre = "Sergio"
edad = 19
nota_fp1 = 7.5
matriculado = True
pendiente = None         # None: "todavía no hay valor"

print(type(nombre))
print(type(edad))
print(type(nota_fp1))
print(type(matriculado))
print(type(pendiente))
print(type(7), type(7.0), type("7"))   # el mismo 7, tres tipos distintos
<class 'str'>
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'NoneType'>
<class 'int'> <class 'float'> <class 'str'>

La última línea es la que más enseña: el mismo 7 escrito de tres formas da tres tipos distintos. 7 es un int, 7.0 es un float (basta el punto) y "7" es un str (bastan las comillas). Para ti son «un siete»; para Python son tres cosas que se comportan de forma diferente.

<class 'int'> es la forma que tiene Python de decir «esto es de tipo int». En Python todo valor es un objeto de alguna clase; lo entenderás del todo cuando llegues a las clases en FP2. De momento, lee class como «tipo».

bool: True y False también son números

Los booleanos salen, sobre todo, de comparaciones. Y tienen una curiosidad muy útil: por dentro, bool es un tipo de int, así que True vale 1 y False vale 0.

aprobado = 7.5 >= 5          # una comparación da un bool
print(aprobado, type(aprobado))
print(True + True + False)   # bool es un tipo de int: True vale 1 y False vale 0
print(int(True), int(False))
True <class 'bool'>
2
1 0

True + True + False da 2 porque es 1 + 1 + 0. Parece una tontería, pero en los ejercicios lo usamos para contar cuántas asignaturas has aprobado sin escribir ni un if. Fíjate también en las mayúsculas: True y False se escriben así; true sería una variable que no existe.

Tipado dinámico: el nombre no tiene tipo, el objeto sí

Volvamos a la idea de las etiquetas, porque explica dos cosas que sorprenden mucho al principio: qué pasa cuando haces copia = nota y por qué una variable puede cambiar de tipo.

# Las variables son etiquetas que apuntan a objetos
nota = 7
copia = nota             # copia apunta al MISMO objeto 7: no se crea otro 7
print(nota, copia, nota is copia)

nota = nota + 1          # se crea el objeto 8 y la etiqueta nota se mueve a él
print(nota, copia, nota is copia)

dato = 19                # un nombre no tiene tipo fijo: ahora apunta a un int...
print(dato, type(dato))
dato = "diecinueve"      # ...y ahora a un str. Python no se queja
print(dato, type(dato))
7 7 True
8 7 False
19 <class 'int'>
diecinueve <class 'str'>

Vamos línea a línea con una tabla de traza (qué apunta a qué después de cada instrucción):

Instrucciónnota apunta acopia apunta anota is copia
nota = 77——
copia = nota7el mismo 7True
nota = nota + 18 (objeto nuevo)7False

El operador is pregunta «¿estas dos etiquetas están pegadas al mismo objeto?». Después de copia = nota la respuesta es True: no se ha copiado el 7, solo se ha pegado una segunda etiqueta. Y cuando haces nota = nota + 1, Python no modifica el 7: calcula un 8 nuevo y despega la etiqueta nota para pegarla al 8. La etiqueta copia no se entera de nada y sigue en el 7:

Qué pasa al reasignar una variablePaso 1: nota y copia apuntan al mismo objeto 7. Paso 2: tras nota = nota + 1 se crea el objeto 8, la etiqueta nota se mueve a él y copia sigue apuntando al 7.1 · copia = notanotacopia7intnota is copia → True2 · nota = nota + 1notacopia8intobjeto nuevo7nota is copia → False
Asignar no cambia el 7: crea un 8 y mueve la etiqueta nota. Por eso copia sigue valiendo 7.

La segunda mitad del programa enseña el tipado dinámico en estado puro: dato apunta primero a un int y luego a un str. Python no se queja, porque el tipo no está en el nombre: está en el objeto. Que se pueda no significa que sea buena idea; si una variable cambia de tipo a mitad de programa, el código se vuelve difícil de seguir.

Con números y textos este comportamiento no da sustos, porque no se pueden modificar (son inmutables): siempre se crea un objeto nuevo. Con las listas sí habrá sorpresas, y por eso más adelante hay un tema entero de mutabilidad y copias. Quédate con el dibujo de las etiquetas: te servirá entonces.

El error que comete todo el mundo con input()

Aquí está la causa del gancho. input() siempre devuelve un str, escriba lo que escriba el usuario. Si tecleas 19, lo que llega a tu programa es el texto "19". En el artículo no usamos input() para que todas las salidas sean reales y reproducibles, así que escribo directamente el texto que te devolvería:

# input() SIEMPRE devuelve texto, aunque escribas un número
edad = "19"              # lo que devuelve input("¿Cuántos años tienes? ") si tecleas 19
print(type(edad))
print(edad + 1)          # str + int: TypeError
<class 'str'>
Traceback (most recent call last):
  File "input_texto.py", line 4, in <module>
    print(edad + 1)          # str + int: TypeError
          ~~~~~^~~
TypeError: can only concatenate str (not "int") to str

type(edad) lo confirma: <class 'str'>. Y el mensaje del error es de los más claros de Python: can only concatenate str (not «int») to str, «solo puedo concatenar (pegar) un str a otro str, no un int». Para Python, + entre textos significa pegar, y no sabe pegar un número a un texto.

La solución es convertir el texto al tipo que necesitas en cuanto lo lees:

edad = int(input("¿Cuántos años tienes? "))       # entero
nota = float(input("Nota del examen: "))          # decimal
nombre = input("¿Cómo te llamas? ")               # texto: no hace falta convertir

Se lee de dentro hacia fuera: primero input() devuelve el texto y después int() lo convierte en número. Así la variable edad nace ya como int.

Convertir de un tipo a otro

Las funciones de conversión se llaman igual que los tipos: int(), float(), str() y bool(). Cada una crea un objeto nuevo del tipo pedido (no cambia el original):

# Convertir de un tipo a otro: int(), float(), str() y bool()
edad = int("19")              # texto -> entero
nota = float("7.5")           # texto -> decimal
print(edad + 1, nota * 2)

print(str(19) + " años")      # número -> texto, para poder pegarlo a otro texto
print(int(7.9))               # float -> int CORTA los decimales, no redondea
print(round(7.9))             # para redondear de verdad, round()
print(float(19))              # int -> float: le añade el .0
print(int("  19  "))          # los espacios de los lados no molestan
print(bool(0), bool(19), bool(""), bool("False"))
20 15.0
19 años
7
8
19.0
19
False True False True

Comprobemos las cuentas: int("19") + 1 da 20 y float("7.5") * 2 da 15.0 (es float, por eso lleva .0). Hay dos resultados que pillan a casi todo el mundo:

  • int(7.9) da 7, no 8. int() corta los decimales; no redondea. Si quieres redondear, usa round(7.9), que da 8.
  • bool("False") da True. Para bool() cualquier texto que no esté vacío es verdadero, aunque diga «False». Solo "", 0, 0.0 y None dan False.

Y luego está la conversión que falla. int() solo entiende textos que sean enteros:

# int() solo entiende textos de números ENTEROS
nota = "7.5"             # lo que devuelve input() si tecleas 7.5
print(float(nota))       # float() sí lo entiende
print(int(float(nota)))  # el camino en dos pasos: "7.5" -> 7.5 -> 7
print(int(nota))         # int("7.5") directamente: ValueError
7.5
7
Traceback (most recent call last):
  File "int_decimal.py", line 5, in <module>
    print(int(nota))         # int("7.5") directamente: ValueError
          ~~~^^^^^^
ValueError: invalid literal for int() with base 10: '7.5'

float("7.5") funciona, int(float("7.5")) funciona (dos pasos: texto → 7.5 → 7), pero int("7.5") directamente da ValueError: invalid literal for int() with base 10. Traducido: «eso no es un entero escrito en base 10». El dibujo resume las cinco conversiones que acabas de ver, con la que falla en rojo:

Conversiones entre tiposCinco conversiones: int de "19" da 19; float de "7.5" da 7.5; int de "7.5" da ValueError; int de 7.9 da 7 porque corta los decimales; str de 19 da el texto "19".TienesLlamas aObtienes"19"strint()19int"7.5"strfloat()7.5float"7.5"strint()ValueError7.9floatint()7intcorta, no redondea19intstr()"19"str
Cada flecha crea un objeto nuevo de otro tipo. La fila roja es el error que más vas a ver con input().

Usar int(input(...)) para una nota. Funciona mientras el usuario escribe 7… y explota el día que escribe 7.5. Para notas, precios, alturas o temperaturas, float().

Otro ValueError muy nuestro: escribir el decimal con coma. float("1,78") falla, porque Python solo entiende el punto. Lo verás en directo en la práctica, con el programa del IMC.

El otro error clásico: el «número» que no es número

Este es el primo del error de input(), y el que explica el 78.5 del gancho. Un número y un texto que parece un número no se comportan igual con los mismos operadores:

a = 5               # número entero
b = "5"             # texto que PARECE un número
print(a + a)        # suma: 10
print(b + b)        # concatena: 55
print(b * 3)        # repite el texto: 555
print(a * 3)        # multiplica: 15
print(len(b), type(b))
print(a + int(b))   # convertir antes de operar: 10
print(a + b)        # mezclar int y str: TypeError
10
55
555
15
1 <class 'str'>
10
Traceback (most recent call last):
  File "cinco.py", line 9, in <module>
    print(a + b)        # mezclar int y str: TypeError
          ~~^~~
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Línea a línea:

ExpresiónTiposResultadoQué hace
a + aint + int10Suma
b + bstr + str55Concatena (pega)
b * 3str * int555Repite el texto 3 veces
a * 3int * int15Multiplica
len(b)len(str)1Cuenta caracteres: "5" tiene uno
a + int(b)int + int10Convierte primero y luego suma
a + bint + strTypeErrorPython no adivina qué querías

Fíjate en que print(b + b) enseña 55 sin comillas: print() nunca muestra las comillas de un texto, y por eso el resultado parece un número. Es exactamente lo que me pasó con el 78.5.

Si un resultado te sale «demasiado grande» o con cifras pegadas (55, 78.5, 1020), sospecha de un str. Ponle un print(type(variable)) justo antes y saldrás de dudas en un segundo.

Los float no son exactos

Tercera sorpresa, y esta no es culpa tuya. Mira:

# Los float se guardan en binario y algunos decimales no caben exactos
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(round(0.1 + 0.2, 2))

# En tu ficha: 30 créditos a 18.32 € el crédito, pagados en 3 plazos
total = 30 * 18.32
plazo = total / 3
print(total)
print(plazo)
print(round(plazo, 2))
print(f"{plazo:.2f} €")
0.30000000000000004
False
0.3
549.6
183.20000000000002
183.2
183.20 €

¿0.1 + 0.2 da 0.30000000000000004? ¿Y 0.1 + 0.2 == 0.3 da False? No es un fallo de Python: los float se guardan en binario, y igual que 1/3 no cabe exacto en decimal (0.3333…), 0.1 no cabe exacto en binario. Se guarda el valor más cercano posible y, al sumar, los pequeños sobrantes asoman.

En la ficha pasa con dinero de verdad: 30 créditos a 18,32 € son 549.6 € (la cuenta a mano: 30 × 18,32 = 549,60), pero al dividir entre 3 plazos sale 183.20000000000002 en lugar de 183,20. Las dos formas de arreglarlo para enseñarlo son:

  • round(plazo, 2) → el número 183.2 (sigue siendo float; round no añade ceros al final).
  • f"{plazo:.2f} €" → el texto 183.20 €, siempre con dos decimales. Es lo que quieres en un recibo.

Comparar dos float con == y fiarte del resultado. 0.1 + 0.2 == 0.3 es False. Redondea antes de comparar (round(x, 2) == 0.3) o compara si la diferencia es muy pequeña; lo verás en el tema de operadores.

Los apuntes de FP1 lo explican con la representación en coma flotante: el número se guarda como una mantisa y un exponente, con un tamaño limitado, y por eso muchos reales solo se pueden guardar de forma aproximada. De ahí viene el nombre float.

¿Qué tipo uso para cada dato?

Antes de escribir un programa, decide el tipo de cada dato. Esta tabla te ahorra la mitad de los errores del tema:

Si el dato…UsaEjemplo de la ficha
Se cuenta (no hay «medio»)intasignaturas, créditos, edad, personas
Se mide o lleva decimalesfloatnotas, precios, altura, temperatura
Es texto, o un número con el que no vas a operarstrnombre, DNI, teléfono, código postal
Responde sí o noboolmatriculado, aprobado
Todavía no existeNonela nota de un examen que no has hecho

El caso del teléfono o el código postal es curioso: son «números», pero nunca los vas a sumar, y si los guardas como int pierdes el cero inicial (int("08001") da 8001). Por eso van como str.

Errores típicos con variables y tipos de datos

Sumar lo que devuelve input() sin convertirlo. "7" + "8.5" da "78.5" (pega) y "7" + 1 da TypeError. Convierte al leer: float(input(...)).

int("7.5"). Da ValueError. Si el dato puede llevar decimales, float(); si de verdad quieres un entero, int(float("7.5")).

Escribir decimales con coma: nota = 7,5 no da error, pero crea una tupla (7, 5), no el número 7.5. Y float("7,5") da ValueError. En Python, siempre punto.

Pensar que int(7.9) redondea. Corta: da 7. Para redondear, round().

Escribir true, false o none en minúscula. Python los toma por nombres de variable y da NameError. Son True, False y None.

Míralo paso a paso en Python Tutor

Python Tutor ejecuta tu código línea a línea y dibuja las variables y los objetos a los que apuntan. Es la mejor forma de ver la idea de las etiquetas con tus propios ojos. Elige Python 3, pega este programa y pulsa Visualize Execution:

nota = 7
copia = nota             # dos etiquetas, un solo objeto 7
nota = nota + 1          # nota se mueve al 8; copia sigue en el 7

edad_txt = "19"          # así llega un dato de input()
edad = int(edad_txt)     # objeto nuevo, de tipo int

media = (7 + 8.5 + 6) / 3
aprobado = media >= 5
tipo_media = type(media)

print(nota, copia, edad)
print(round(media, 2), aprobado, tipo_media)

Al final, la salida es esta:

8 7 19
7.17 True <class 'float'>

Qué observar, avanzando con Next:

  1. Después de copia = nota: en la columna Frames verás nota y copia con el mismo valor 7. Python Tutor dibuja los números pequeños dentro de la variable, pero recuerda el dibujo de las etiquetas: los dos nombres apuntan al mismo objeto.
  2. Después de nota = nota + 1: nota pasa a 8 y copia se queda en 7. La asignación ha movido una etiqueta; no ha tocado el 7.
  3. Después de edad = int(edad_txt): conviven edad_txt, con "19" entre comillas (un str), y edad, con 19 sin comillas (un int). Mismo dígito, distinto tipo.
  4. Después de media = …: media vale 7.166666666666667. La media de 7, 8.5 y 6 no es exacta, y Python enseña todos los decimales que guarda.
  5. En tipo_media = type(media): fíjate en que un tipo también es un objeto al que se puede apuntar con un nombre. El print final lo enseña como <class 'float'>.

En las opciones de Python Tutor puedes cambiar inline primitives por render all objects on the heap. Entonces los números también se dibujan como objetos aparte, con flechas, y verás exactamente el dibujo de las etiquetas.

Resumen

ConceptoLo esencialEjemplo
VariableUn nombre que apunta a un objeto; se crea al asignaredad = 19
AsignaciónPrimero la derecha, luego el nombreedad = edad + 1
Tipos básicosint, float, str, bool (y None)19, 7.5, "GCID", True
type()Te dice el tipo del objetotype(7.5) → <class 'float'>
Tipado dinámicoEl tipo va en el objeto, no en el nombredato = 19 y luego dato = "diecinueve"
input()Siempre devuelve strfloat(input("Nota: "))
Conversionesint(), float(), str(), bool(): crean objetos nuevosint("19") → 19
"5" frente a 5+ pega textos y suma números"5" + "5" → 55
floatAproximado: redondea para enseñarf"{x:.2f}"

Tres ideas para llevarte:

  1. Una variable es una etiqueta pegada a un objeto, y el tipo lo lleva el objeto.
  2. Todo lo que entra por input() es texto: conviértelo nada más leerlo.
  3. Los float son aproximados: redondea al final y nunca compares decimales con == a ciegas.

Con los tipos claros, ya puedes calcular, comparar y combinar condiciones. Eso es justo el siguiente tema: operadores en Python, donde verás //, %, ** y por qué 5 / 2 da 2.5. Pero antes, ponlo en práctica con la nota media, el IMC y el precio de tu matrícula.

Siguiente paso: prácticaVariables 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)

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