Formato de cadenas e input()
En la lección anterior viste cómo construir mensajes uniendo cadenas con +:
>>> nombre = "cristina"
>>> edad = 25
>>> mensaje = "hola " + nombre + ", tienes " + str(edad) + " años"
>>> print(mensaje)
hola cristina, tienes 25 años
Funciona, pero tiene tres problemas evidentes: los + ensucian la lectura, hay que recordar añadir espacios manualmente, y hay que convertir los números a string con str() para no provocar un TypeError. Python ofrece una sintaxis mucho más limpia para esto: las f-strings.
Sintaxis básica de las f-strings
Una f-string es una cadena prefijada con la letra f. Dentro de ella, todo lo que pongas entre llaves { } se sustituye por el valor de esa expresión:
>>> nombre = "cristina"
>>> edad = 25
>>> print(f"hola {nombre}, tienes {edad} años")
hola cristina, tienes 25 años
Se leen casi como leerías la frase final. No hace falta concatenar, ni convertir los números, ni preocuparse por los espacios: todo lo que está fuera de las llaves se imprime tal cual.
Nota: la f tiene que estar pegada a las comillas, sin espacio. Si te olvidas de la f, las llaves se imprimirán literalmente como parte del texto. Es uno de los errores más fáciles de cometer.
>>> print("hola {nombre}") # sin la f, las llaves son literales
hola {nombre}
Expresiones dentro de las llaves
Dentro de las llaves no estás limitado a poner nombres de variables. Puedes escribir cualquier expresión de Python: operaciones, llamadas a métodos, llamadas a funciones, comparaciones, accesos a listas o diccionarios... Python evalúa la expresión y mete el resultado:
>>> nombre = "cristina"
>>> precio = 12.5
>>> cantidad = 3
>>> print(f"hola {nombre.title()}")
hola Cristina
>>> print(f"total: {precio * cantidad}")
total: 37.5
>>> print(f"la cadena tiene {len(nombre)} letras")
la cadena tiene 8 letras
>>> print(f"¿es adulto? {edad >= 18}")
¿es adulto? True
Esta capacidad es la que convierte a las f-strings en una herramienta de propósito general: sustituyen tanto a la concatenación con + como al uso de print() con varios argumentos separados por comas.
Especificadores de formato
Dentro de las llaves puedes añadir, después de dos puntos, indicaciones sobre cómo quieres que se muestre el valor. La sintaxis general es {valor:especificador}.
Decimales
Para números con coma flotante, lo más habitual es controlar cuántos decimales mostrar. :.2f redondea a dos decimales:
>>> precio = 7.5
>>> iva = 0.21
>>> total = precio * (1 + iva)
>>> print(f"total: {total}")
total: 9.075
>>> print(f"total: {total:.2f} €")
total: 9.08 €
El número antes de la f es la cantidad de decimales. :.0f muestra el número como entero (redondeando), :.4f mostraría cuatro decimales.
Anchura y alineación
Si quieres alinear texto en columnas, indica una anchura mínima. Por defecto los números se alinean a la derecha y el texto a la izquierda, pero puedes forzarlo con < (izquierda), > (derecha) o ^ (centro):
>>> for fruta, precio in [("manzana", 1.2), ("pera", 0.8), ("sandía", 3.5)]:
... print(f"{fruta:<10} {precio:>6.2f} €")
manzana 1.20 €
pera 0.80 €
sandía 3.50 €
Aquí {fruta:<10} reserva diez caracteres alineados a la izquierda para el nombre, y {precio:>6.2f} reserva seis caracteres alineados a la derecha para el precio con dos decimales. El resultado es una tabla ordenada sin tener que contar espacios a mano.
Relleno con ceros
Para números con relleno de ceros a la izquierda (típico en horas, identificadores, etc.), usa 0 seguido de la anchura:
>>> for h in [7, 18, 23]:
... print(f"{h:02d}:00")
07:00
18:00
23:00
Separador de miles
Para números grandes, una coma como especificador inserta el separador de miles (en estilo anglosajón). Si prefieres puntos al estilo español, sustitúyelos luego con .replace():
>>> poblacion = 1234567
>>> print(f"{poblacion:,}")
1,234,567
>>> print(f"{poblacion:,}".replace(",", "."))
1.234.567
Cadenas de varias líneas
Si el texto se hace largo, puedes usar triples comillas para escribirlo en varias líneas. Sigue funcionando como f-string si añades la f delante:
>>> nombre = "cristina"
>>> ciudad = "zaragoza"
>>> edad = 25
>>> ficha = f"""
... Nombre: {nombre.title()}
... Ciudad: {ciudad.title()}
... Edad: {edad}
... """
>>> print(ficha)
Nombre: Cristina
Ciudad: Zaragoza
Edad: 25
El truco = para depurar
Si pones un signo igual al final de la expresión dentro de las llaves, Python imprime tanto el nombre como el valor. Es muy útil cuando estás depurando código y quieres ver qué tiene cada variable sin escribir su nombre dos veces:
>>> x = 7
>>> y = 12
>>> print(f"{x=}, {y=}, {x + y=}")
x=7, y=12, x + y=19
Nota: este truco existe desde Python 3.8. Es para uso de depuración: en código de producción es más limpio escribir el mensaje completo.
Comillas dentro de una f-string
Como cualquier cadena, una f-string usa unas comillas para delimitarse. Si necesitas el mismo tipo de comillas dentro, alterna comillas simples y dobles, o escápalas con barra invertida:
>>> usuario = "ignacio"
>>> print(f"hola, '{usuario}'") # comillas simples dentro de dobles
hola, 'ignacio'
>>> print(f'hola, "{usuario}"') # comillas dobles dentro de simples
hola, "ignacio"
Antes de las f-strings: .format() y %
Las f-strings se introdujeron en Python 3.6 (año 2016). En código más antiguo verás dos formas anteriores que cumplen la misma función:
# método .format(): sigue siendo válido
>>> print("hola {}, tienes {} años".format(nombre, edad))
hola cristina, tienes 25 años
# operador %: estilo C, muy antiguo
>>> print("hola %s, tienes %d años" % (nombre, edad))
hola cristina, tienes 25 años
Funcionan, pero son más verbosos y menos legibles. En código nuevo usa siempre f-strings; conoce las otras dos solo para saber leer código antiguo cuando te lo encuentres.
Leer datos del teclado: input()
Hasta ahora todos los datos los hemos escrito directamente en el código. Para pedirle algo al usuario por teclado, Python ofrece la función integrada input(). El programa se detiene esperando que el usuario escriba algo y pulse Enter, y devuelve lo escrito como una cadena:
>>> nombre = input("¿Cómo te llamas? ")
¿Cómo te llamas? cristina
>>> print(f"hola, {nombre}")
hola, cristina
El argumento de input() es el texto que se muestra antes de leer (el prompt). No es obligatorio, pero conviene dejar claro al usuario qué se espera de él.
Nota: input() siempre devuelve una cadena (str), incluso si el usuario escribe un número. Si necesitas tratarlo como número, tienes que convertirlo explícitamente con int() o float().
>>> edad = input("¿Cuántos años tienes? ")
¿Cuántos años tienes? 25
>>> print(edad + 1) # error: edad es "25" (cadena)
TypeError: can only concatenate str (not "int") to str
>>> edad = int(input("¿Cuántos años tienes? "))
¿Cuántos años tienes? 25
>>> print(edad + 1)
26
El patrón int(input(...)) o float(input(...)) es muy habitual. Tiene un riesgo: si el usuario escribe algo que no es un número, int() lanza un ValueError y el programa falla. Los métodos .isdigit() que vimos en la lección de strings, o el manejo de excepciones con try/except que verás más adelante, son las dos formas de protegerse contra eso.
Un ejemplo que combina todo
Un mini programa que aplica lo de esta lección y la anterior:
nombre = input("¿Cómo te llamas? ").strip().title()
edad = int(input("¿Cuántos años tienes? "))
altura = float(input("¿Cuánto mides en metros? "))
print(f"""
Hola, {nombre}.
Tienes {edad} años y mides {altura:.2f} m.
{"Ya eres mayor de edad." if edad >= 18 else "Aún eres menor de edad."}
""")
Fíjate en tres cosas: .strip().title() encadena dos métodos de cadena para limpiar el espacio sobrante y poner mayúscula inicial; {altura:.2f} formatea el número con dos decimales; y dentro de las llaves se puede usar incluso el operador ternario if/else que vimos en condicionales.
En la próxima lección: otros tipos de datos en Python: números enteros y decimales, booleanos, None, y la función type() para saber con qué estás trabajando.