🖨️ Fundamentos de print()
En esta primera parte aprenderás a usar una de las funciones más importantes de Python: print()
.
Con ella podrás mostrar mensajes, resultados de operaciones y cualquier información en pantalla.
Es la base de toda interacción entre el programa y el usuario.
📦 Sintaxis básica y múltiple
La función print()
se utiliza para imprimir texto o valores en la consola.
print("Hola, mundo!")
Salida:
Hola, mundo!
También puedes imprimir varios elementos separados por comas:
print("El resultado es", 10 + 5)
Salida:
El resultado es 15
💡 Python convierte automáticamente los valores numéricos, cadenas o booleanos a texto al usar print()
, por lo que no necesitas transformarlos con str()
.
📋 Tabla resumen — Uso básico de print()
Ejemplo | Salida | Descripción |
---|---|---|
print("Hola") | Hola | Imprime una cadena de texto |
print(2 + 3) | 5 | Evalúa una operación aritmética |
print("Edad:", 30) | Edad: 30 | Combina texto y números |
print(True) | True | Imprime un valor booleano |
⚙️ Parámetros sep
y end
La función print()
tiene dos parámetros muy útiles:
sep
: define el separador entre los elementos.end
: define lo que se imprime al final de la línea (por defecto es un salto de línea\n
).
Ejemplo con sep
:
print("Python", "es", "genial", sep="-")
Salida:
Python-es-genial
Ejemplo con end
:
print("Hola", end=" ")
print("mundo!")
Salida:
Hola mundo!
💡 sep
y end
se usan mucho cuando quieres controlar el formato exacto del texto.
📁 Parámetros avanzados: file
y flush
Por defecto, print()
escribe en la salida estándar (pantalla), pero puedes enviarlo a un archivo usando file=
.
with open("salida.txt", "w") as archivo:
print("Guardando texto en un archivo.", file=archivo)
Esto crea (o sobrescribe) un archivo salida.txt
con el texto dentro.
🌀 El parámetro flush
Por rendimiento, la salida se almacena temporalmente en memoria (buffer).
Si quieres forzar la escritura inmediata, usa flush=True
:
print("Procesando...", flush=True)
Esto es útil cuando estás mostrando progreso en tiempo real (por ejemplo, en scripts largos o interfaces de consola).
🔤 Secuencias de escape y saltos de línea
Dentro de las cadenas puedes usar caracteres especiales que comienzan con una barra invertida (\
).
Secuencia | Significado | Ejemplo | Salida |
---|---|---|---|
\n | Salto de línea | print("Hola\nMundo") | Hola Mundo |
\t | Tabulación | print("A\tB\tC") | A B C |
\\ | Imprime una barra invertida | print("Ruta C:\\Archivos") | Ruta C:\Archivos |
\" | Comillas dobles dentro de texto | print("Ella dijo: \"Hola\"") | Ella dijo: «Hola» |
También puedes usar cadenas raw (crudas) anteponiendo una r
, para que no interprete los escapes:
print(r"C:\nueva\carpeta") # No interpreta \n como salto
Salida:
C:\nueva\carpeta
🧩 Ejemplos prácticos con print()
Ejemplo 1: Imprimir varios tipos de datos
nombre = "Javier"
edad = 32
activo = True
print("Usuario:", nombre, "| Edad:", edad, "| Activo:", activo)
Usuario: Javier | Edad: 32 | Activo: True
Ejemplo 2: Mostrar resultados de operaciones
a, b = 5, 3
print("Suma:", a + b)
print("Multiplicación:", a * b)
print("División:", a / b)
Suma: 8
Multiplicación: 15
División: 1.6666666666666667
Ejemplo 3: Uso combinado de sep y end
print("Cargando", end="")
for i in range(3):
print(".", end="", flush=True)
print(" ¡Listo!")
Cargando... ¡Listo!
📚 Resumen de la Parte 1
print()
muestra información por pantalla o archivos.- Usa
sep
yend
para personalizar la salida. - Los parámetros
file
yflush
controlan la salida avanzada. - Las secuencias de escape permiten incluir saltos, tabulaciones o comillas.
- Combina texto y variables fácilmente:
print("Edad:", edad)
.
🎨 Formateo y presentación de salida
Imprimir “algo” funciona. Imprimirlo bonito y claro es otro nivel.
En esta parte aprenderás a formatear salidas con f-strings (recomendado), str.format()
y el estilo antiguo con %
.
También verás alineación, anchos fijos, precisión decimal, separadores de miles y cómo mostrar Unicode/emoji.
💡 F-strings (recomendado)
Las f-strings (desde Python 3.6) son la forma más clara y moderna de formatear texto.
Se antepone una f
a la cadena y se insertan expresiones entre llaves {}
.
nombre = "Javier"
edad = 32
print(f"Hola, {nombre}. Tienes {edad} años.")
Las f-strings admiten expresiones y especificadores de formato tras dos puntos :
dentro de las llaves.
precio = 19.9876
print(f"Precio: {precio:.2f} €") # 2 decimales
porcentaje = 0.2567
print(f"Tasa: {porcentaje:.1%}") # porcentaje con 1 decimal
entero = 1234567
print(f"Entero con miles: {entero:,}") # separador de miles (,) → 1,234,567
Especificador | Significado | Ejemplo | Salida |
---|---|---|---|
:.2f | 2 decimales | f"{3.14159:.2f}" | 3.14 |
:.0f | 0 decimales (redondea) | f"{9.8:.0f}" | 10 |
:+d | Signo para enteros | f"{7:+d}" | +7 |
:08d | Ancho 8, relleno con 0 | f"{42:08d}" | 00000042 |
:, | Separador de miles | f"{1234567:,}" | 1,234,567 |
:.1% | Porcentaje | f"{0.256:.1%}" | 25.6% |
:^10 | Alinear centrado (ancho 10) | f"{'OK':^10}" | OK |
También puedes usar expresiones y llamadas dentro de las llaves:
def iva(precio, tasa=0.21):
return precio * (1 + tasa)
p = 50
print(f"Total con IVA: {iva(p):.2f} €") # Llama a la función dentro del formato
🧩 Método str.format()
y mini-lenguaje
str.format()
fue el estándar antes de las f-strings y sigue siendo útil.
nombre = "Ana"
edad = 28
print("Hola, {}. Tienes {} años.".format(nombre, edad))
print("Hola, {n}. Tienes {e} años.".format(n=nombre, e=edad))
print("Precio: {:.2f} €".format(19.9876))
Soporta índice de posición, nombres y especificadores idénticos a los de f-strings:
print("{:>10}".format("OK")) # Alineado a la derecha (ancho 10)
print("{:^10}".format("OK")) # Centrado
print("{:<10}".format("OK")) # Alineado a la izquierda
print("{:08d}".format(42)) # 00000042
print("{:,}".format(1234567)) # 1,234,567
📼 Estilo antiguo con %
(heredado)
Menos recomendado, pero aún lo verás en código legacy.
nombre = "Lucía"
edad = 30
print("Hola, %s. Tienes %d años." % (nombre, edad))
print("Pi ≈ %.3f" % 3.1415926)
Marcador | Tipo | Ejemplo | Salida |
---|---|---|---|
%s | cadena | "%s" % "hola" | hola |
%d | entero | "%d" % 7 | 7 |
%.2f | float (2 dec.) | "%.2f" % 3.1 | 3.10 |
📏 Ancho, alineación y precisión
Formatear columnas ayuda a construir tablas legibles en consola.
productos = [
("Manzanas", 3, 0.6),
("Peras", 12, 0.75),
("Plátanos", 100, 0.33),
]
# Encabezado
print(f"{'Producto':<12} {'Unidades':>8} {'Precio':>8}")
print("-" * 30)
# Filas
for nombre, unidades, precio in productos:
print(f"{nombre:<12} {unidades:>8d} {precio:>8.2f}")
Salida aproximada:
Producto Unidades Precio
------------------------------
Manzanas 3 0.60
Peras 12 0.75
Plátanos 100 0.33
Claves del mini-lenguaje (en f-strings y format()
):
Patrón | Significado | Ejemplo |
---|---|---|
{x:<10} | Alinea a la izquierda, ancho 10 | f"{'OK':<10}" |
{x:>10} | Alinea a la derecha, ancho 10 | f"{'OK':>10}" |
{x:^10} | Centrado, ancho 10 | f"{'OK':^10}" |
{n:08d} | Rellena con ceros (8) | f"{42:08d}" |
{v:.3f} | 3 decimales | f"{3.14159:.3f}" |
{v:,} | Separador de miles | f"{1234567:,}" |
🌍 Unicode, acentos y emoji
Python 3 usa UTF-8 por defecto en código fuente. Puedes imprimir acentos y emoji sin drama:
print("Café ☕ — Precio: 2,50 €")
print("Bandera España: \U0001F1EA\U0001F1F8")
Si escribes a archivo y tienes lío de acentos, especifica encoding="utf-8"
:
with open("salida.txt", "w", encoding="utf-8") as f:
print("Café ☕ — Precio: 2,50 €", file=f)
🖼️ Pretty print para estructuras (dict/list)
Para diccionarios y listas complejas, usa pprint
para una salida “bonita”.
from pprint import pprint
datos = {
"usuario": "jcachon",
"roles": ["admin", "editor", "report"],
"perfil": {"nombre": "Javier", "activo": True, "edad": 32}
}
pprint(datos, sort_dicts=False, width=60)
🧪 Casos prácticos
1) Tickets y facturas
lineas = [
("Teclado mecánico", 1, 79.9),
("Ratón inalámbrico", 2, 24.5),
("Alfombrilla XXL", 1, 17.9),
]
print(f"{'Artículo':<20} {'Ud':>3} {'Precio':>8} {'Total':>8}")
print("-" * 45)
total = 0
for art, ud, pr in lineas:
t = ud * pr
total += t
print(f"{art:<20} {ud:>3d} {pr:>8.2f} {t:>8.2f}")
print("-" * 45)
print(f"{'TOTAL':>33} {total:>10.2f} €")
2) Reportes con porcentaje y miles
usuarios = 1234567
crecimiento = 0.0342
print(f"Usuarios: {usuarios:,} | Crecimiento: {crecimiento:.2%}")
3) Tabla alineada con cabeceras
cab = ("ID", "Nombre", "Score")
rows = [(1, "Ana", 9.5), (23, "Luis", 7.25), (305, "Marta", 8.0)]
print(f"{cab[0]:>4} {cab[1]:<10} {cab[2]:>6}")
print("-" * 24)
for i, n, s in rows:
print(f"{i:>4d} {n:<10} {s:>6.2f}")
✅ Resumen
- Usa f-strings para legibilidad y potencia (
{expr:formato}
). str.format()
sigue siendo válido; el estilo%
es legacy.- Controla ancho, alineación, rellenos y precisión con el mini-lenguaje de formato.
- Gestiona Unicode/emoji sin problemas; usa
encoding="utf-8"
en archivos. pprint
hace más legible la impresión de estructuras complejas.
⌨️ Fundamentos de input()
La función input()
es la herramienta básica para pedir información al usuario.
Cada vez que se ejecuta, el programa se detiene y espera a que el usuario escriba algo en la consola.
Cuando se presiona Enter, el texto ingresado se devuelve como una cadena (str
).
📥 Sintaxis básica y prompt
Su sintaxis es muy sencilla:
nombre = input("¿Cómo te llamas? ")
print("Hola,", nombre)
Cuando se ejecuta:
¿Cómo te llamas? Javier
Hola, Javier
El texto entre comillas dentro de input()
es el prompt (mensaje que se muestra al usuario).
💡 Si no se pasa ningún texto, el prompt estará vacío y el cursor parpadeará esperando entrada:
dato = input()
print("Has escrito:", dato)
🔢 Conversión de tipos (casting)
Todo lo que devuelve input()
es una cadena.
Si necesitas un número o un valor lógico, debes convertirlo explícitamente con las funciones de tipo.
Tipo deseado | Función | Ejemplo | Entrada → Resultado |
---|---|---|---|
Entero | int() | int(input()) | “25” → 25 |
Decimal | float() | float(input()) | “3.14” → 3.14 |
Texto | str() | str(input()) | “Hola” → “Hola” |
Lógico | bool() | bool(input()) | ⚠️ Siempre True si hay texto |
Ejemplo completo:
edad = int(input("Introduce tu edad: "))
print("El año que viene tendrás", edad + 1, "años.")
Salida:
Introduce tu edad: 32
El año que viene tendrás 33 años.
💡 Importante: si el usuario introduce algo no convertible (por ejemplo, letras en lugar de un número), se producirá un ValueError
.
Por eso, aprenderás en el siguiente punto cómo manejar esos errores con try/except
.
🧱 Validación y manejo de errores
Es buena práctica asegurarse de que la entrada del usuario sea válida antes de usarla.
El control de errores se hace con try/except
.
try:
numero = int(input("Introduce un número entero: "))
print("Has escrito el número", numero)
except ValueError:
print("❌ Error: Debes introducir un número válido.")
Salida:
Introduce un número entero: hola
❌ Error: Debes introducir un número válido.
Validar rangos:
try:
edad = int(input("Edad: "))
if edad < 0:
print("❌ La edad no puede ser negativa.")
elif edad > 120:
print("⚠️ Edad poco realista.")
else:
print("✅ Edad registrada:", edad)
except ValueError:
print("❌ Introduce un número entero.")
✂️ Limpieza de entradas (strip, lower, upper)
El texto introducido puede tener espacios, mayúsculas o caracteres indeseados.
Python ofrece métodos útiles para “limpiar” la cadena antes de procesarla:
Método | Función | Ejemplo | Resultado |
---|---|---|---|
strip() | Elimina espacios iniciales y finales | " hola ".strip() | "hola" |
lower() | Convierte a minúsculas | "PYTHON".lower() | "python" |
upper() | Convierte a mayúsculas | "python".upper() | "PYTHON" |
capitalize() | Primera letra mayúscula | "python".capitalize() | "Python" |
Ejemplo:
respuesta = input("¿Deseas continuar? (sí/no): ").strip().lower()
if respuesta == "sí" or respuesta == "si":
print("Continuando el programa...")
else:
print("Programa finalizado.")
⚙️ Lectura de múltiples valores
También puedes pedir varios datos en una sola línea y separarlos con split()
.
entrada = input("Introduce tres números separados por espacios: ")
a, b, c = map(int, entrada.split())
print("Suma:", a + b + c)
Salida:
Introduce tres números separados por espacios: 3 4 5
Suma: 12
💡 split()
divide la cadena por espacios, pero puedes usar otro separador:
# Con comas
numeros = input("Introduce números separados por coma: ")
lista = [int(x) for x in numeros.split(",")]
print("Lista:", lista)
Introduce números separados por coma: 5,10,15
Lista: [5, 10, 15]
🧠 Resumen de la Parte 3
input()
pausa el programa y devuelve una cadena (str
).- Usa funciones de conversión:
int()
,float()
,str()
. - Controla errores con
try/except
para evitar bloqueos. - Limpia la entrada con
strip()
,lower()
y similares. - Divide y procesa varios valores con
split()
omap()
.
🤝 Flujo interactivo, seguridad y UX
En esta parte aprenderás cómo crear programas que dialoguen con el usuario: pedir datos, validarlos, repetirlos si son incorrectos y hacerlo de manera clara y segura.
Además, verás cómo proteger entradas sensibles (como contraseñas) y mejorar la experiencia general del usuario.
🔁 Bucles de reintento y mensajes útiles
Cuando el usuario comete un error al introducir un valor, lo ideal es volver a pedirlo sin que el programa se bloquee.
Esto se consigue fácilmente con bucles while
y control de errores.
while True:
try:
edad = int(input("Introduce tu edad: "))
if edad <= 0:
print("⚠️ La edad debe ser un número positivo.")
else:
print(f"Perfecto, tienes {edad} años.")
break
except ValueError:
print("❌ Error: Introduce un número válido.")
💡 Este patrón se conoce como input loop: el usuario no puede avanzar hasta que proporcione una entrada válida.
💬 Personalizando mensajes
La claridad es clave. Usa frases amables y precisas.
Evita mensajes genéricos o técnicos como “Error de tipo” o “Entrada inválida”.
Un ejemplo más humano:
while True:
nombre = input("Escribe tu nombre: ").strip()
if len(nombre) < 2:
print("❌ El nombre es demasiado corto, inténtalo de nuevo.")
else:
print(f"Hola, {nombre}! Encantado de conocerte.")
break
🔒 Entradas sensibles con getpass
Cuando necesitas solicitar contraseñas o datos confidenciales, nunca uses input()
.
Python ofrece el módulo getpass
que oculta la entrada del usuario mientras escribe.
from getpass import getpass
usuario = input("Usuario: ")
clave = getpass("Contraseña: ")
if usuario == "admin" and clave == "1234":
print("✅ Acceso concedido.")
else:
print("❌ Acceso denegado.")
💡 Al ejecutar este código en consola, los caracteres de la contraseña no se muestran ni siquiera con asteriscos —es la forma más segura y profesional de pedir contraseñas.
🧱 Buenas prácticas de seguridad
Las entradas del usuario pueden ser peligrosas si no se validan correctamente.
Aquí tienes algunas reglas esenciales:
- 🔸 Nunca uses
eval()
oexec()
con texto ingresado por el usuario. - 🔸 Valida siempre el formato, longitud y contenido de los datos.
- 🔸 En campos sensibles (contraseñas, tokens), utiliza
getpass
o cifrado. - 🔸 Si el programa manipula archivos, controla rutas y extensiones.
Ejemplo de mala práctica ❌
# ¡PELIGRO! No hagas esto
expr = input("Escribe una expresión: ")
print(eval(expr)) # Permite ejecutar código arbitrario
Ejemplo de buena práctica ✅
expr = input("Escribe una expresión matemática: ")
try:
resultado = float(eval(expr, {"__builtins__": None}, {})) # Controla entorno
print("Resultado:", resultado)
except Exception:
print("⚠️ Entrada no válida.")
Aun así, lo mejor es implementar tus propias funciones de evaluación seguras (por ejemplo, con ast.literal_eval
o expresiones regulares).
🌍 Localización: separadores y formatos
En distintos países, los números se escriben de forma diferente:
por ejemplo, 3.14
frente a 3,14
.
Si esperas usuarios internacionales, puedes usar el módulo locale
para gestionar formatos numéricos.
import locale
locale.setlocale(locale.LC_ALL, '') # Usa la configuración regional del sistema
numero = 12345.6789
print("Número local:", locale.format_string("%.2f", numero, grouping=True))
Esto mostrará el número con los separadores y decimales apropiados para la región del usuario.
🧠 Patrones de prompts “amables”
Una buena interfaz de texto debe ser amigable, coherente y minimalista.
Aquí tienes algunos consejos prácticos:
Mal prompt ❌ | Buen prompt ✅ |
---|---|
input("Edad: ") | input("Por favor, introduce tu edad (en años): ") |
input("Sexo: ") | input("Selecciona tu sexo (H/M): ") |
input("Clave: ") | getpass("Introduce tu contraseña: ") |
Ejemplo final — diálogo completo
from getpass import getpass
print("=== Registro de usuario ===")
while True:
nombre = input("Nombre de usuario: ").strip()
if len(nombre) < 3:
print("⚠️ El nombre debe tener al menos 3 caracteres.")
continue
clave = getpass("Contraseña (mínimo 6 caracteres): ")
if len(clave) < 6:
print("⚠️ La contraseña es demasiado corta.")
continue
print(f"✅ Usuario {nombre} registrado correctamente.")
break
💬 Este tipo de flujo evita frustraciones y da al usuario un feedback inmediato y claro.
📋 Resumen de la Parte 4
- Repite entradas inválidas usando bucles
while
con validación. - Oculta contraseñas con
getpass()
. - Evita funciones inseguras como
eval()
sin control. - Usa
locale
para mostrar números según la región. - Escribe prompts amables y descriptivos para mejorar la UX.
🧰 I/O avanzado: streams, archivos y pruebas
En esta parte subirás de nivel: trabajarás con flujos estándar (STDIN/STDOUT/STDERR), leerás y escribirás archivos, gestionarás codificaciones, redirigirás/capturarás salidas y aprenderás cuándo usar print()
y cuándo logging
.
🧵 STDIN / STDOUT / STDERR con sys
Python expone tres flujos estándar en el módulo sys
:
Flujo | Uso | Cuándo |
---|---|---|
sys.stdin | Entrada estándar | Leer datos (pipes, redirección, terminal) |
sys.stdout | Salida estándar | Mensajes normales / resultados |
sys.stderr | Salida de errores | Alertas, trazas, advertencias |
import sys
# Escribir sin salto de línea automático
sys.stdout.write("Procesando")
sys.stdout.write("...\n")
# Mensaje de error (separado de la salida normal)
sys.stderr.write("⚠️ Aviso: archivo no encontrado\n")
💡 Separar stdout
de stderr
permite redirigirlos por separado en consola (p. ej., guardar solo resultados y mostrar errores en pantalla).
📁 Archivos: leer y escribir con seguridad
La forma profesional de trabajar con archivos es mediante el context manager with
, que cierra el archivo automáticamente.
Abrir y escribir (texto)
# "w" = escribir (crea o sobrescribe)
with open("salida.txt", "w", encoding="utf-8") as f:
f.write("Hola, archivo 👋\n")
f.write("Línea 2\n")
Leer todo el contenido
with open("salida.txt", "r", encoding="utf-8") as f:
contenido = f.read()
print(contenido)
Leer línea a línea (memoria eficiente)
with open("salida.txt", "r", encoding="utf-8") as f:
for linea in f:
print(">", linea.rstrip())
Modos de apertura más usados
Modo | Significado | Notas |
---|---|---|
"r" | Leer | Falla si no existe |
"w" | Escribir | Sobrescribe |
"a" | Añadir | Escribe al final |
"x" | Crear | Falla si existe |
"b" | Binario | Combinar: "rb" , "wb" |
"+" | Lectura/Escritura | p. ej. "r+" |
Binario (imágenes, PDFs…)
# Copiar un archivo binario
with open("foto.jpg", "rb") as src, open("copia.jpg", "wb") as dst:
dst.write(src.read())
Gestión de errores con archivos
from pathlib import Path
ruta = Path("datos.txt")
try:
with ruta.open("r", encoding="utf-8") as f:
print(f.readline().strip())
except FileNotFoundError:
print("❌ Archivo no encontrado:", ruta)
except PermissionError:
print("❌ Permisos insuficientes para:", ruta)
🌍 Codificaciones y saltos de línea
Usa siempre encoding="utf-8"
para evitar problemas con acentos/emoji.
Controla los saltos de línea con newline=
si trabajas datos multi-plataforma.
# Escribir CSV compatible (Windows/macOS/Linux)
import csv
rows = [("id","nombre"), (1,"Javier"), (2,"Ana")]
with open("usuarios.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)
💡 En Windows, el manejo de newline=""
evita líneas en blanco extra en CSV.
🔀 Redirección y captura de salida
En la terminal (Bash, PowerShell)
# Redirigir salida estándar a un archivo
python mi_script.py > salida.log
# Redirigir errores a otro archivo
python mi_script.py 2> errores.log
# Redirigir ambos (stdout y stderr)
python mi_script.py > todo.log 2>&1
# Encadenar por pipe
python generar.py | python procesar.py
Capturar salida en Python (pruebas / utilidades)
import io
from contextlib import redirect_stdout, redirect_stderr
buffer_out = io.StringIO()
buffer_err = io.StringIO()
print("Inicio")
with redirect_stdout(buffer_out):
print("Esto va a stdout capturado")
with redirect_stderr(buffer_err):
import sys
sys.stderr.write("Esto va a stderr capturado\\n")
print("Fin")
print("CAPTURA STDOUT:", buffer_out.getvalue().strip())
print("CAPTURA STDERR:", buffer_err.getvalue().strip())
💡 Útil para tests, generar informes o integrar scripts con otras herramientas.
🧭 print()
vs logging
: ¿cuál usar y cuándo?
Regla de oro: usa print()
para interacción directa con el usuario; usa logging
para diagnóstico y observabilidad.
print() | logging |
---|---|
Mensajes al usuario / outputs sencillos | Registros del sistema, depuración, auditoría |
No tiene niveles | Niveles: DEBUG, INFO, WARNING, ERROR, CRITICAL |
Difícil de desactivar globalmente | Configuración centralizada, filtros y handlers |
Siempre va a stdout | Puede ir a archivos, consola, syslog, HTTP, etc. |
Ejemplo de configuración básica de logging
import logging
logging.basicConfig(
level=logging.INFO, # Nivel mínimo a registrar
format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
log = logging.getLogger("app")
def conectar(db_url):
log.debug("Iniciando conexión...")
# ...
log.info("Conectado a %s", db_url)
def procesar(dato):
if not dato:
log.warning("Dato vacío, se omite")
return
# ...
log.error("Error de ejemplo: %s", "detalle del error")
conectar("postgresql://localhost")
procesar("")
Enviar logs a archivo y consola
import logging
logger = logging.getLogger("pipeline")
logger.setLevel(logging.DEBUG)
# Handler a archivo
fh = logging.FileHandler("pipeline.log", encoding="utf-8")
fh.setLevel(logging.INFO)
# Handler a consola
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# Formato común
fmt = logging.Formatter("%(levelname)s | %(message)s")
fh.setFormatter(fmt)
ch.setFormatter(fmt)
logger.addHandler(fh)
logger.addHandler(ch)
logger.info("Inicio del pipeline")
logger.debug("Detalle de depuración visible solo en consola")
🧪 Patrones de prueba: entrada/salida
Probar funciones que dependen de input()
/print()
es más fácil si separas lógica de I/O.
Aun así, puedes simular entradas y capturar salidas con io.StringIO
.
import io, sys
def saludo():
nombre = input("Nombre: ")
print(f"Hola, {nombre}")
# Simular input y capturar output
entrada = io.StringIO("Javier\n")
salida = io.StringIO()
sys.stdin, sys.stdout = entrada, salida # ⚠️ manipulación global controlada
try:
saludo()
finally:
# Restablecer
sys.stdin, sys.stdout = sys.__stdin__, sys.__stdout__
print("CAPTURA:", salida.getvalue().strip())
✅ En frameworks como pytest, usarías los fixtures capsys
/capfd
para capturar salidas sin tocar sys
manualmente.
🧾 Checklist de I/O profesional
- Usa
with open(...)
yencoding="utf-8"
. - Separa stdout y stderr para redirigir mejor.
- Para datos tabulares, usa
csv
ynewline=""
. - Captura salida en pruebas con
redirect_stdout
/StringIO
. - Elige
print()
para UX,logging
para registros.