Entrada y salida en Python: print(), input() y formateo de strings
- Por qué importa la E/S desde el primer programa
- print(): mucho más que imprimir texto
- Los parámetros sep y end
- file, flush y otros usos avanzados
- input(): leer datos del usuario
- El problema con los tipos en input()
- f-strings: el formateo moderno
- f-strings avanzadas: formato, alineación, debug
- Los otros métodos de formateo
- Programa completo: tarjeta de presentación
- Errores clásicos con E/S
- Preguntas frecuentes
Hay un momento muy concreto en que un programa deja de ser un ejercicio abstracto y se convierte en algo útil: cuando empieza a hablar con el usuario. Cuando le pregunta algo, espera la respuesta, y le devuelve algo significativo. Ese puente entre el programa y la persona que lo usa es la entrada y salida, y en Python tiene una elegancia que a mí todavía me sigue gustando después de años.
En esta lección vamos a explorar print() de verdad, no solo el uso básico que ya conoces, sino todos sus parámetros y los patrones que hacen el output realmente útil. Luego input(), con su trampa clásica de los tipos. Y después la parte que más me gusta enseñar: las f-strings, que son una de las razones por las que el código Python moderno es tan agradable de leer.
🖨️ print(): mucho más que imprimir texto
Ya has usado print() desde la primera lección. Pero probablemente lo has usado solo en su forma más simple: print("algo"). La función tiene cuatro parámetros opcionales que cambian completamente lo que puedes hacer con ella.
# La firma completa de print():
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
# Lo que ya conoces:
print("Hola, mundo") # → Hola, mundo
print(42) # → 42
print(3.14) # → 3.14
print(True) # → True
# Varios valores a la vez:
print("Tu edad es", 28, "años") # → Tu edad es 28 años
print(1, 2, 3, 4, 5) # → 1 2 3 4 5
# Sin argumentos — imprime una línea vacía:
print() # → (línea en blanco)
Esa última forma, print() sin argumentos, la uso constantemente para añadir espacio visual entre bloques de salida. Es más limpio que print("").
🔧 Los parámetros sep y end: más útiles de lo que parecen
sep controla qué carácter se pone entre los valores cuando imprimes varios a la vez. Por defecto es un espacio. end controla qué se pone al final de la línea. Por defecto es '\n' (salto de línea).
# sep: separador entre valores
print(2026, 3, 6, sep="-") # → 2026-3-6
print("ruta", "al", "archivo", sep="/") # → ruta/al/archivo
print("a", "b", "c", sep=", ") # → a, b, c
print("junto", "todo", sep="") # → juntotodo
# end: qué va al final
print("cargando", end="")
print("...") # → cargando... (en la misma línea)
print("uno", end=" | ")
print("dos", end=" | ")
print("tres") # → uno | dos | tres
# Imprimir lista sin bucle explícito:
numeros = [1, 2, 3, 4, 5]
print(*numeros, sep=" → ") # → 1 → 2 → 3 → 4 → 5
print(*lista, sep="\n") imprime cada elemento de la lista en su propia línea sin necesidad de un bucle. Es el atajo elegante que uso constantemente para debuggear listas rápidamente.
Barra de progreso en terminal con end y flush
import time
for i in range(1, 6):
print(f"Procesando paso {i}/5...", end="\r", flush=True)
time.sleep(0.5)
print("Completado. ") # espacios para borrar el texto anterior
El end="\r" vuelve al principio de la línea sin bajar, sobreescribiendo el mensaje anterior. El flush=True fuerza que aparezca inmediatamente. Sin él, en algunos sistemas el texto queda en el buffer y no se ve hasta que el programa termina.
📁 file y flush: redirigir la salida
El parámetro file acepta cualquier objeto con un método .write(). El uso más habitual: escribir a un archivo de log directamente con print(), sin importar el módulo logging.
import sys
# Imprimir en stderr (mensajes de error) en lugar de stdout
print("Error: archivo no encontrado", file=sys.stderr)
# Escribir a un archivo de log
with open("registro.log", "a") as log:
print("2026-03-06 09:00 - Inicio de proceso", file=log)
print("2026-03-06 09:01 - Paso 1 completado", file=log)
# El archivo queda cerrado automáticamente al salir del with
# Combinar con sep para generar CSV:
cabeceras = ["nombre", "edad", "ciudad"]
datos = ["Ana", 28, "Madrid"]
with open("datos.csv", "w") as f:
print(*cabeceras, sep=",", file=f)
print(*datos, sep=",", file=f)
logging, que da control sobre niveles de severidad, formato y destinos múltiples. La redirección con file= es útil para scripts simples o depuración rápida, no para sistemas en producción.
⌨️ input(): leer datos del usuario
input() detiene la ejecución del programa, muestra un mensaje opcional, y espera a que el usuario escriba algo y pulse Enter. Lo que devuelve es siempre un str.
# Forma básica
nombre = input("¿Cómo te llamas? ")
print(f"Hola, {nombre}!")
# Sin mensaje (no recomendable — el usuario no sabe qué hacer)
dato = input()
# El mensaje puede ser lo que quieras
print("Por favor, introduce tu nombre:")
nombre = input("> ")
# Captura múltiple
nombre = input("Nombre: ")
ciudad = input("Ciudad: ")
print(f"Registrado: {nombre} de {ciudad}")
input("Tu nombre: ") en lugar de input("Tu nombre:"). Sin el espacio, el cursor queda pegado a los dos puntos y la línea queda visualmente incómoda para el usuario.
🔄 El problema con los tipos en input()
Esta es la trampa número uno para los principiantes, sin excepción. input() siempre devuelve un string, aunque el usuario escriba un número. Si necesitas operar con él matemáticamente, tienes que convertirlo explícitamente.
# El error clásico:
edad = input("Tu edad: ") # el usuario escribe 28
print(edad + 10) # TypeError: can only concatenate str (not "int") to str
# La solución: convertir al tipo correcto
edad = int(input("Tu edad: "))
print(edad + 10) # → 38
# Para decimales:
precio = float(input("Precio: "))
# Pero ¿y si el usuario escribe algo que no es un número?
# La conversión falla con ValueError. La solución robusta:
try:
edad = int(input("Tu edad: "))
except ValueError:
print("Eso no es un número válido.")
edad = 0
El patrón int(input(...)) con el try/except es tan común que conviene aprenderlo como una unidad. Cuando lleguemos al módulo de manejo de excepciones veremos formas más elegantes, pero por ahora esto es lo que necesitas.
# Patrón completo para pedir un número al usuario de forma robusta:
def pedir_entero(mensaje):
while True:
try:
return int(input(mensaje))
except ValueError:
print("Por favor, introduce un número entero.")
edad = pedir_entero("Tu edad: ")
print(f"Tienes {edad} años.")
✨ f-strings: el formateo moderno
Las f-strings llegaron en Python 3.6 y cambiaron la forma en que todo el mundo escribe código Python. La idea es simple: pones una f antes de la comilla de apertura y puedes incluir expresiones Python directamente dentro del string usando llaves {}.
nombre = "Ana"
edad = 28
ciudad = "Madrid"
# La forma pre-f-strings (todavía válida pero más verbosa):
saludo = "Hola, %s. Tienes %d años y vives en %s." % (nombre, edad, ciudad)
saludo = "Hola, {}. Tienes {} años y vives en {}.".format(nombre, edad, ciudad)
# Con f-strings — mucho más limpio:
saludo = f"Hola, {nombre}. Tienes {edad} años y vives en {ciudad}."
# Las llaves pueden contener cualquier expresión Python:
f"El doble de tu edad es {edad * 2}" # → "El doble de tu edad es 56"
f"Nombre en mayúsculas: {nombre.upper()}" # → "Nombre en mayúsculas: ANA"
f"¿Eres mayor de edad? {'Sí' if edad >= 18 else 'No'}" # → "¿Eres mayor de edad? Sí"
f"Suma: {2 + 2}" # → "Suma: 4"
🎛️ f-strings avanzadas: formato, alineación y debug
Las f-strings tienen un mini-lenguaje de especificación de formato que te permite controlar decimales, ancho de campo, alineación y mucho más. La sintaxis es {valor:especificador}.
precio = 1234.5678
pi = 3.14159265358979
# Decimales
f"{precio:.2f}" # → "1234.57" (2 decimales, redondea)
f"{pi:.4f}" # → "3.1416"
# Separador de miles
f"{1000000:,}" # → "1,000,000"
f"{precio:,.2f}" # → "1,234.57"
# Ancho de campo y alineación
f"{'izquierda':<20}" # → "izquierda " (alineado a la izq.)
f"{'centro':^20}" # → " centro " (centrado)
f"{'derecha':>20}" # → " derecha" (alineado a la dcha.)
f"{42:>10}" # → " 42"
# Relleno con un carácter específico
f"{'título':*^30}" # → "************título************"
f"{42:0>5}" # → "00042"
# Porcentaje
tasa = 0.1575
f"{tasa:.1%}" # → "15.8%"
# Notación científica
f"{0.000123:.2e}" # → "1.23e-04"
El truco de debug con = (Python 3.8+)
Uno de mis favoritos para depuración rápida:
x = 42
y = [1, 2, 3]
nombre = "Ana"
# En lugar de print("x =", x, "y =", y):
print(f"{x=}") # → x=42
print(f"{y=}") # → y=[1, 2, 3]
print(f"{nombre=}") # → nombre='Ana'
print(f"{x=}, {y=}") # → x=42, y=[1, 2, 3]
# También funciona con expresiones:
print(f"{x * 2 = }") # → x * 2 = 84
print(f"{a=}, {b=}, {c=}") en lugar de print("a:", a, "b:", b, "c:", c). Menos teclas, más información.
📋 Los otros métodos de formateo
Las f-strings son la opción por defecto en Python 3.6+, pero vale la pena conocer las alternativas porque las verás en código existente y hay casos donde son la herramienta correcta.
str.format()
# Posicional:
"Hola, {}. Tienes {} años.".format("Ana", 28)
# Con nombres (más legible en plantillas largas):
"{nombre} vive en {ciudad}.".format(nombre="Ana", ciudad="Madrid")
# Reutilización:
"{0} + {0} = {1}".format(5, 10) # → "5 + 5 = 10"
# Mismo especificador de formato que f-strings:
"{:.2f}".format(3.14159) # → "3.14"
.format() sigue siendo útil cuando necesitas plantillas de texto que defines en un lugar y rellenas en otro, o cuando el string viene de una base de datos o archivo de configuración.
Formateo antiguo con %
"Hola, %s" % "Ana" # → "Hola, Ana"
"Precio: %.2f€" % 9.99 # → "Precio: 9.99€"
"%d items en %s" % (3, "cesta") # → "3 items en cesta"
El operador % viene del estilo C y sigue funcionando, pero en código nuevo no tiene ventajas sobre las f-strings. Lo verás mucho en código de hace más de 5-8 años.
🛠️ Programa completo: tarjeta de presentación
Vamos a juntar todo lo visto en un programa que pide datos al usuario y genera una tarjeta de presentación formateada.
print("=== GENERADOR DE TARJETA DE PRESENTACIÓN ===")
print()
nombre = input("Tu nombre completo: ")
cargo = input("Tu cargo o profesión: ")
empresa = input("Empresa u organización: ")
ciudad = input("Ciudad: ")
try:
anos_exp = int(input("Años de experiencia: "))
except ValueError:
anos_exp = 0
ancho = 40
linea = "=" * ancho
print()
print(linea)
print(f" {nombre.title():^{ancho - 4}}")
print(f" {cargo:<{ancho - 4}}")
print(f" {empresa:<{ancho - 4}}")
print(f" 📍 {ciudad:<{ancho - 6}}")
if anos_exp > 0:
print(f" ⭐ {anos_exp} años de experiencia")
print(linea)
print()
print(f"Tarjeta generada para {nombre.split()[0]}. ¡Listo!")
Ejemplo de ejecución con los datos de una persona:
# Entrada:
# Tu nombre completo: ana garcía
# Tu cargo o profesión: Desarrolladora Python
# Empresa u organización: Ciberaula
# Ciudad: Madrid
# Años de experiencia: 5
# Salida:
# ========================================
# Ana García
# Desarrolladora Python
# Ciberaula
# 📍 Madrid
# ⭐ 5 años de experiencia
# ========================================
🐛 Errores clásicos con entrada y salida
1. Olvidar convertir el resultado de input()
n = input("Un número: ")
print(n * 3) # Si escribes 5: imprime "555" no 15
# Porque "5" * 3 = "555" en Python (repetición de string)
# Correcto:
n = int(input("Un número: "))
print(n * 3) # → 15
2. Concatenar string + int sin convertir
edad = 28
print("Tengo " + edad + " años") # TypeError
# Opciones correctas:
print("Tengo " + str(edad) + " años")
print("Tengo", edad, "años")
print(f"Tengo {edad} años") # La más limpia
3. Olvidar las llaves en una f-string
nombre = "Ana"
print(f"Hola nombre") # → "Hola nombre" (sin las llaves no se sustituye)
print(f"Hola {nombre}") # → "Hola Ana" ✅
4. Usar f-string sin la f
nombre = "Ana"
saludo = "Hola, {nombre}" # string normal, no f-string
print(saludo) # → "Hola, {nombre}" (literal)
saludo = f"Hola, {nombre}" # ✅
5. Llaves literales en una f-string
# Si necesitas imprimir llaves reales en una f-string, duplícalas:
f"El formato es {{variable}}" # → "El formato es {variable}"
f"{{{nombre}}}" # → "{Ana}"
✅ Resumen y próximos pasos
print() tiene cuatro parámetros: sep para el separador entre valores, end para el final de línea, file para redirigir la salida y flush para escritura inmediata. input() siempre devuelve un string — recuerda convertir con int() o float() cuando sea necesario. Y para formatear strings, las f-strings son la opción por defecto en cualquier código Python moderno.
En la siguiente lección entramos en el control de flujo: if, elif y else. Con input() e if juntos ya puedes escribir programas interactivos reales que toman decisiones según lo que diga el usuario.
❓ Preguntas frecuentes
❓ Preguntas frecuentes sobre Entrada y salida en Python: print(), input() y formateo de strings
Las dudas más comunes respondidas de forma clara y directa.
💬 Foro de discusión
¿Tienes dudas sobre Entrada y salida en Python: print(), input() y formateo de strings? Comparte tu pregunta con la comunidad.
Todavía no hay mensajes. ¡Sé el primero en participar!