Saltar al contenido
entrada-y-salida.py · devschool

Entrada y salida en Python: print, input y f-strings

Lección 5 de 31 · 15 min de lectura · Actualizado el

En esta lección
  1. print a fondo
  2. input: leer lo que escribe el usuario
  3. Convertir lo que llega como texto
  4. Validar la entrada con try y except
  5. f-strings a fondo
  6. Ejemplo completo: un ticket de compra
  7. Las formas antiguas: str.format y %
  8. Errores frecuentes
  9. Resumen

Casi todos los programas hacen lo mismo: reciben datos, los procesan y muestran un resultado. En Python, la salida por pantalla se hace con print() y la entrada por teclado con input(). Ya los usaste en la introducción; en esta lección los verás a fondo: todos los parámetros de print, cómo convertir y validar lo que escribe el usuario sin que el programa se rompa, y cómo dar formato profesional a números, tablas y fechas con las f-strings.

print acepta cualquier número de valores, de cualquier tipo, y los muestra separados por un espacio:

producto = "zapatillas"
talla = 42
precio = 59.9
print("Has elegido", producto, "talla", talla, "por", precio, "€")
# Has elegido zapatillas talla 42 por 59.9 €

No hace falta convertir los números a texto: print llama a str() sobre cada valor por ti. Esa es una diferencia importante con el operador +, que solo une textos.

sep: el separador entre valores

El parámetro sep (de separator) cambia lo que se pone entre los valores. Por defecto es un espacio:

print("05", "10", "2026", sep="/")
print("ana", "gmail.com", sep="@")
print("Pan", "Leche", "Huevos", sep="\n")
# 05/10/2026
# ana@gmail.com
# Pan
# Leche
# Huevos

Con sep="\n" cada valor sale en su línea. Y con el operador *, que reparte una lista en argumentos sueltos, puedes imprimir una lista entera con el separador que quieras:

ruta = ["Covadonga", "Lagos", "Vega de Ario", "Caín"]
print(*ruta, sep=" -> ")
# Covadonga -> Lagos -> Vega de Ario -> Caín

end: qué se escribe al final

Por defecto, cada print termina con un salto de línea ("\n"). El parámetro end lo sustituye por lo que quieras. Así puedes escribir varias cosas en la misma línea con varios print:

for vuelta in range(1, 6):
    print(vuelta, end=" ")
print()          # salto de línea final
print("Series completadas", end="!\n")
# 1 2 3 4 5 
# Series completadas!

El print() vacío del medio solo escribe un salto de línea: sin él, el siguiente texto saldría pegado a los números.

file: a dónde va el texto

Normalmente print escribe en la salida estándar (sys.stdout), que es la pantalla. Con file puedes mandarlo a otro sitio. El caso más habitual es la salida de errores (sys.stderr), un canal separado para mensajes de error:

import sys

print("Procesando pedidos...")
print("Aviso: falta el código postal del pedido 17", file=sys.stderr)
# Procesando pedidos...
# Aviso: falta el código postal del pedido 17

En la terminal los dos mensajes se ven igual, pero son canales distintos: si rediriges la salida de tu programa a un fichero (python programa.py > informe.txt), los avisos de stderr seguirán apareciendo en pantalla. file también acepta un fichero abierto con open(), como verás en Ficheros.

flush: mostrar el texto ya

Python no siempre escribe en pantalla al instante: a veces acumula el texto en un búfer (una zona de memoria intermedia) y lo vuelca de golpe, porque es más rápido. Casi nunca lo notarás, pero en una barra de progreso que se escribe con end="" puede que no veas nada hasta el final. flush=True obliga a mostrarlo en el momento:

import time

print("Descargando", end="", flush=True)
for _ in range(3):
    time.sleep(0.1)
    print(".", end="", flush=True)
print(" hecho")
# Descargando... hecho

Nota: print siempre devuelve None. Por eso resultado = print("hola") guarda None, no el texto. print sirve para mostrar; para devolver un valor desde una función usa return.

input: leer lo que escribe el usuario

input() muestra un mensaje, espera a que el usuario escriba algo y pulse Enter, y devuelve lo escrito como texto (str), sin el salto de línea final:

nombre = input("¿Cómo te llamas? ")
edad = input("¿Cuántos años tienes? ")
print(f"Hola, {nombre}. Tipo de edad: {type(edad).__name__}")
# ¿Cómo te llamas? Lucía
# ¿Cuántos años tienes? 19
# Hola, Lucía. Tipo de edad: str

Aunque el usuario escriba 19, edad es el texto "19". Si intentas sumarle 1 obtendrás TypeError. Hay que convertirlo con int() o float().

Nota: input() necesita a alguien escribiendo en una terminal, así que en el editor de esta web no funciona igual. En el resto de la lección, los datos del usuario se simulan con variables de texto, para que puedas ejecutar todos los ejemplos. En tu ordenador, cambia esas variables por input(...) y funcionará igual.

Convertir lo que llega como texto

Las funciones de conversión más usadas son int(), float() y str(). Además, conviene limpiar el texto antes de convertirlo:

respuesta = "  42 \n"            # simula lo que podría llegar de input()
unidades = int(respuesta)        # int ignora los espacios de los extremos
print(unidades * 2)              # 84

precio_texto = "12,50"           # en España se escribe la coma decimal
precio = float(precio_texto.replace(",", "."))
print(precio)                    # 12.5

confirmar = " SÍ "
print(confirmar.strip().lower() in ("sí", "si", "s"))   # True

Tres trucos que usarás a menudo:

  • int y float aceptan espacios al principio y al final, pero no letras ni la coma decimal.
  • .replace(",", ".") permite que el usuario escriba 12,50 como está acostumbrado.
  • .strip().lower() normaliza respuestas tipo sí/no, para no depender de mayúsculas ni espacios.

Varios datos en una línea

Si pides varios números a la vez (por ejemplo, "3 8 5"), sepáralos con split() y convierte cada trozo:

linea = "7.5 8 6.25"                       # simula input("Notas: ")
notas = [float(n) for n in linea.split()]
print(notas)                               # [7.5, 8.0, 6.25]

alto, ancho = map(int, "180 90".split())   # dos valores en dos variables
print(alto * ancho)                        # 16200

map(int, ...) aplica int a cada trozo. Si llegan más o menos valores de los esperados, el desempaquetado falla con ValueError.

Validar la entrada con try y except

¿Qué pasa si el usuario escribe "doce" cuando esperabas un número? int("doce") lanza un ValueError y, si no lo capturas, el programa se detiene. Con try/except (lo verás a fondo en Excepciones) puedes reaccionar al error:

def a_entero(texto):
    """Convierte un texto en entero o devuelve None si no es válido."""
    try:
        return int(texto)
    except ValueError:
        return None

for prueba in ["25", " 3 ", "doce", "4.5", ""]:
    print(repr(prueba), "->", a_entero(prueba))
# '25' -> 25
# ' 3 ' -> 3
# 'doce' -> None
# '4.5' -> None
# '' -> None

Fíjate en que int("4.5") también falla: int solo acepta textos con números enteros. Si quieres admitir decimales, usa float.

Repetir la pregunta hasta que sea válida

En un programa real con teclado, lo habitual es preguntar en bucle hasta recibir un dato correcto. Este es el patrón clásico (pruébalo en tu ordenador):

while True:
    texto = input("Edad (0-120): ")
    try:
        edad = int(texto)
    except ValueError:
        print("Escribe un número entero, por favor.")
        continue
    if 0 <= edad <= 120:
        break
    print("La edad debe estar entre 0 y 120.")

print(f"Edad registrada: {edad}")
# Edad (0-120): veinte
# Escribe un número entero, por favor.
# Edad (0-120): 200
# La edad debe estar entre 0 y 120.
# Edad (0-120): 20
# Edad registrada: 20

Hay dos comprobaciones distintas: que el texto sea un número (try/except) y que el número tenga sentido (el if del rango). continue vuelve al principio del bucle y break lo termina cuando todo es correcto.

Para no depender del teclado, aquí tienes la misma lógica en una función que recibe las respuestas en una lista, como si el usuario las hubiera escrito una tras otra:

def pedir_edad(respuestas):
    for texto in respuestas:
        try:
            edad = int(texto)
        except ValueError:
            print(f"'{texto}' no es un número")
            continue
        if 0 <= edad <= 120:
            return edad
        print(f"{edad} está fuera de rango")
    return None

print("Edad:", pedir_edad(["veinte", "200", "20"]))
# 'veinte' no es un número
# 200 está fuera de rango
# Edad: 20

Consejo: separar la lógica (validar un texto) de la entrada (input) hace tu código más fácil de probar. Es la misma idea que usarás más adelante con las pruebas automáticas.

f-strings a fondo

Una f-string es un texto con una f delante en el que puedes meter cualquier expresión entre llaves. Ya conoces lo básico de Variables y tipos; ahora veamos todo lo que admite el formato, que va después de dos puntos:

{valor:[relleno][alineación][signo][ancho][,][.precisión][tipo]}

No hace falta aprenderlo de memoria: basta con conocer las piezas más útiles.

Decimales, miles y signo

total = 1234567.891
print(f"{total:.2f}")      # 1234567.89
print(f"{total:,.2f}")     # 1,234,567.89
print(f"{total:_.0f}")     # 1_234_568
print(f"{3:+d} {-3:+d}")   # +3 -3
print(f"{0.000123:.2e}")   # 1.23e-04
  • .2f: número decimal (float) con 2 cifras tras el punto. Redondea, no corta.
  • , o _: separador de miles.
  • +: muestra siempre el signo, útil para variaciones (“+3 puntos”).
  • e: notación científica.

El separador de miles sigue el estilo inglés (coma para miles, punto para decimales). Para el formato español, intercambia los símbolos:

def euros(cantidad):
    texto = f"{cantidad:,.2f}"                     # 1,234,567.89
    texto = texto.replace(",", "X").replace(".", ",").replace("X", ".")
    return texto + " €"

print(euros(1234567.891))   # 1.234.567,89 €
print(euros(9.5))           # 9,50 €

Ancho y alineación

Indicas un ancho mínimo y cómo alinear dentro de él: < izquierda, > derecha, ^ centro. Delante puedes poner un carácter de relleno:

print(f"[{'Ana':<8}]")      # [Ana     ]
print(f"[{'Ana':>8}]")      # [     Ana]
print(f"[{'Ana':^8}]")      # [  Ana   ]
print(f"[{'Ana':*^9}]")     # [***Ana***]
print(f"[{42:>6}]")         # [    42]
print(f"{' MENÚ ':=^24}")   # ========= MENÚ =========

Los textos se alinean a la izquierda por defecto y los números a la derecha. El ancho también puede venir de una variable, metiendo otras llaves dentro del formato:

ancho = 12
print(f"|{'centrado':^{ancho}}|")   # |  centrado  |

Ceros a la izquierda y otras bases

pedido = 7
print(f"PED-{pedido:05d}")    # PED-00007
print(f"{9:02d}:{5:02d}")     # 09:05
print(f"{255:b} {255:x} {255:X} {255:o}")   # 11111111 ff FF 377
print(f"#{255:02x}{128:02x}{0:02x}")        # #ff8000

05d significa “entero (d) de ancho 5 rellenado con ceros”. Es lo que usarías para números de factura, horas o códigos. b, x y o muestran el número en binario, hexadecimal y octal; el último ejemplo construye un color CSS.

Porcentajes

El tipo % multiplica por 100 y añade el símbolo:

aprobados = 23
alumnos = 28
print(f"Aprobados: {aprobados / alumnos:.1%}")   # Aprobados: 82.1%
print(f"Descuento: {0.15:.0%}")                  # Descuento: 15%

Así no tienes que multiplicar por 100 a mano: le pasas la proporción (un número entre 0 y 1) y el formato hace el resto.

Fechas

Los objetos de fecha del módulo datetime aceptan los códigos de strftime directamente en la f-string:

from datetime import datetime

cita = datetime(2026, 10, 5, 9, 30)
print(f"{cita:%d/%m/%Y}")         # 05/10/2026
print(f"{cita:%H:%M}")            # 09:30
print(f"{cita:%d/%m/%Y a las %H:%M}")   # 05/10/2026 a las 09:30

%d es el día, %m el mes, %Y el año con cuatro cifras, %H la hora y %M los minutos. Tienes la lista completa en Fechas.

= para depurar

Si pones = justo después de la expresión, la f-string muestra el texto de la expresión y su valor. Es la forma más rápida de comprobar qué vale algo mientras programas:

precio = 19.99
unidades = 3
print(f"{precio=}, {unidades=}")
print(f"{precio * unidades = :.2f}")
# precio=19.99, unidades=3
# precio * unidades = 59.97

Se puede combinar con un formato después de los dos puntos, como en la segunda línea.

!r, llaves literales y textos largos

ciudad = "Santander"
print(f"Ciudad: {ciudad!r}")           # Ciudad: 'Santander'
print(f"Usa {{nombre}} en la plantilla")   # Usa {nombre} en la plantilla

mensaje = (
    f"Pedido de {ciudad}: "
    f"{unidades} unidades, "
    f"total {precio * unidades:.2f} €"
)
print(mensaje)
# Pedido de Santander: 3 unidades, total 59.97 €
  • !r muestra el valor con repr(), con comillas. Viene bien para ver espacios ocultos en un texto.
  • Para escribir una llave de verdad, duplícala: {{ y }}.
  • Varias f-strings seguidas dentro de paréntesis se unen solas: es la forma limpia de partir un texto largo.

Ejemplo completo: un ticket de compra

Juntamos todo: alineación, decimales, ancho y repetición de caracteres.

cesta = [
    ("Manzanas (kg)", 2.5, 1.89),
    ("Pan integral", 1, 1.35),
    ("Aceite de oliva", 1, 9.75),
    ("Yogures", 8, 0.42),
]

ANCHO = 38
print(f"{'FRUTERÍA LA HUERTA':^{ANCHO}}")
print("-" * ANCHO)
print(f"{'Producto':<18}{'Cant.':>6}{'Importe':>14}")
total = 0
for nombre, cantidad, precio in cesta:
    importe = cantidad * precio
    total += importe
    print(f"{nombre:<18}{cantidad:>6g}{importe:>12.2f} €")
print("-" * ANCHO)
print(f"{'TOTAL':<24}{total:>12.2f} €")
print(f"{'IVA incluido (10 %)':<24}{total - total / 1.10:>12.2f} €")
#           FRUTERÍA LA HUERTA          
# --------------------------------------
# Producto           Cant.       Importe
# Manzanas (kg)        2.5        4.72 €
# Pan integral           1        1.35 €
# Aceite de oliva        1        9.75 €
# Yogures                8        3.36 €
# --------------------------------------
# TOTAL                          19.18 €
# IVA incluido (10 %)             1.74 €

El tipo g muestra el número de la forma más corta: 2.5 se queda igual y 1 no se convierte en 1.0.

Las formas antiguas: str.format y %

Las f-strings existen desde Python 3.6. Antes se usaban otras dos formas que verás en código antiguo y en muchos tutoriales. Usan el mismo mini lenguaje de formato:

nombre = "Marta"
saldo = 1520.5

print("Hola, {}. Tu saldo es {:.2f} €".format(nombre, saldo))
print("Hola, {n}. Tu saldo es {s:,.2f} €".format(n=nombre, s=saldo))
print("Hola, %s. Tu saldo es %.2f €" % (nombre, saldo))
# Hola, Marta. Tu saldo es 1520.50 €
# Hola, Marta. Tu saldo es 1,520.50 €
# Hola, Marta. Tu saldo es 1520.50 €
  • str.format sustituye cada {} por los argumentos, en orden o por nombre. Todavía es útil cuando la plantilla se define antes de tener los datos, por ejemplo guardada en una constante.
  • El operador % es el estilo de C: %s para texto, %d para enteros y %.2f para decimales. Hoy solo lo encontrarás en código antiguo y en el módulo logging.
PLANTILLA = "Reserva de {cliente} para {personas} personas"
print(PLANTILLA.format(cliente="Iñaki", personas=4))
# Reserva de Iñaki para 4 personas

Para todo lo demás, usa f-strings: son más cortas, más rápidas y se leen mejor.

Errores frecuentes

  • Operar con lo que devuelve input sin convertirlo: input("Edad: ") + 1 da TypeError: can only concatenate str (not "int") to str. Convierte con int() o float().
  • Convertir sin validar: int("12,5") o int("") lanzan ValueError y paran el programa. Envuelve la conversión en try/except.
  • Olvidar la f: "Total: {total}" imprime las llaves tal cual. Comprueba que el texto empieza por f".
  • Confundir sep y end: sep va entre valores del mismo print; end, al final de cada print.
  • Usar + para unir textos y números: "Tienes " + 3 + " avisos" falla. Usa una f-string o print con comas.
  • Esperar formato español con :,: el separador de miles es la coma inglesa. Cámbialo con replace si necesitas 1.234,50.
  • Guardar el resultado de print: devuelve None. Para construir un texto y guardarlo, usa una f-string.

Resumen

HerramientaPara qué sirveEjemplo
sepSeparador entre valoresprint(d, m, a, sep="/")
endFinal de cada printprint(x, end=" ")
fileDestino de la salidaprint(msg, file=sys.stderr)
flushMostrar sin esperar al búferprint(".", end="", flush=True)
input()Leer texto del tecladonombre = input("Nombre: ")
int() / float()Convertir texto en númeroint(texto)
try/except ValueErrorValidar la conversiónRepetir la pregunta en un bucle
:.2f / :,Decimales / milesf"{x:,.2f}"
:<10 :>10 :^10Alinear en un anchof"{nombre:<18}"
:05dCeros a la izquierdaf"{7:05d}" -> 00007
:.1%Porcentajef"{0.821:.1%}"
:%d/%m/%YFormato de fechaf"{hoy:%d/%m/%Y}"
{x=}Depurar: nombre y valorf"{precio=}"
.format() / %Formas antiguas"{}".format(x)

En la siguiente lección harás que tus programas tomen decisiones con if, elif y else.

Pon a prueba lo que has aprendido

[Python] ¿Qué se muestra por pantalla?
print("a", "b", sep="")
print("x", end="-")
print("y")

[Python] El usuario escribe 19 en edad = input("Edad: "). ¿Qué imprime print(edad * 2)?

[Python] ¿Cuál de estas conversiones lanza ValueError?

[Python] ¿Qué imprime este código?
print(f"PED-{7:05d} {0.15:.0%} [{'Ana':>6}]")

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.