Herramientas de depuración
Python incluye breakpoint() y pdb, se integra con REPLs más completos como ipdb, admite depuradores de conexión remota y se basa en el registro estructurado para producción. Elija la herramienta adecuada para la reproducción local frente a la observación de sistemas en vivo.
Referencia de herramientas de depuración
| Herramienta | Tipo | Descripción |
|---|---|---|
breakpoint() | punto de entrada del depurador stdlib | Llama al hook sys.breakpoints() (por defecto pdb.set_trace) |
pdb / pdb.pm() | post-mortem | Inspecciona la pila después de una excepción |
ipdb | REPL mejorado | Autocompletado de tabulación y resaltado de sintaxis de IPython |
debugpy | conexión remota | VS Code/PyCharm se conectan a un proceso en ejecución |
logging | señal de producción | Contexto estructurado sin detener hilos |
faulthandler | volcado de fallos | Vuelca el rastro en SIGABRT/hang |
tracemalloc | memoria | Instantáneas de asignación (ver escenarios de memoria) |
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
def charge(amount: int) -> int:
breakpoint() # Python 3.14: respeta PYTHONBREAKPOINT
if amount < 0:
raise ValueError("negativo")
return amount * 100
# post-mortem en pytest: pytest --pdb
# registro:
import logging
log = logging.getLogger(__name__)
log.exception("falló el cargo", extra={"amount": amount})Cuándo usar esto:
- Reproducir un error lógico con variables locales intactas
- Inspeccionar la pila después de una excepción en CI
- Conectarse a un pod de staging sin editar código
- Correlacionar informes de usuarios con registros de solicitudes en producción
Ejemplo de trabajo
import logging
import sys
from contextlib import contextmanager
# --- configuración de registro estructurado ---
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
log = logging.getLogger("billing")
@contextmanager
def request_context(request_id: str):
old = logging.LoggerAdapter(log, {"request_id": request_id})
try:
yield old
finally:
pass
# --- comandos de sesión de pdb (referencia comentada para lectores) ---
# p variable -> imprimir
# n -> siguiente línea
# s -> entrar en paso
# w -> dónde está la pila
# l -> listar código fuente
# c -> continuar
def apply_discount(total_cents: int, pct: int) -> int:
if pct < 0 or pct > 100:
log.error("pct inválido", extra={"pct": pct})
raise ValueError("pct fuera de rango")
discounted = total_cents * (100 - pct) // 100
log.info("descontado", extra={"before": total_cents, "after": discounted})
return discounted
def debug_example() -> None:
# punto de interrupción condicional solo en desarrollo
if sys.flags.debug_mode: # o os.getenv("DEBUG_PDB") == "1"
breakpoint()
print(apply_discount(10_00, 10))
# --- utilidad post-mortem ---
def run_with_pm(fn):
try:
return fn()
except Exception:
import pdb
pdb.post_mortem()
raise
# --- faulthandler para bloqueos ---
import faulthandler
faulthandler.enable()# pytest con pdb en caso de fallo
uv run pytest tests/test_billing.py --pdb -x
# depuración remota (debugpy) - iniciar listener al inicio de la aplicación cuando DEBUG_ATTACH=1
# VS Code se conecta al puerto 5678Lo que esto demuestra:
loggingregistra valores de negocio sin detener los hilos de serviciobreakpoint()se detiene localmente; proteger con una bandera de entorno en rutas de código compartidaspytest --pdbentra en modo post-mortem en fallos de aserciónfaulthandlerayuda cuando los procesos se bloquean sin lanzar excepciones
Inmersión profunda
Cómo funciona
breakpoint()consultaPYTHONBREAKPOINT(por defectopdb.set_trace)- Los depuradores se ejecutan en el mismo proceso; los puntos de interrupción bloquean ese hilo o proceso
debugpyescucha en un puerto; el IDE inyecta puntos de interrupción sin volver a desplegar- El registro debe ser estructurado en producción; pdb es para la reproducción en desarrollo/staging
Lista corta de comandos de pdb
| Comando | Acción |
|---|---|
h | ayuda |
n | siguiente |
s | paso |
r | retorno |
until | ejecutar hasta una línea mayor que la actual |
pp expr | imprimir bonito |
!stmt | ejecutar instrucción de Python |
Notas de Python
# deshabilitar puntos de interrupción en el punto de entrada de producción
import os
if os.getenv("ENVIRONMENT") == "production":
os.environ["PYTHONBREAKPOINT"] = "0"Trampas comunes
- Dejar
breakpoint()en el código principal - detiene los trabajadores de producción. Solución: protección por variable de entorno; ruff puede marcar sentencias de depuración. - Imprimir secretos en pdb - el historial de la sesión registra datos sensibles. Solución: redactar; usar registro con filtros.
- Depuración remota abierta en 0.0.0.0 en producción - riesgo de RCE. Solución: solo en staging, túnel SSH, autenticación.
- Depuración con
printen bucles intensivos - I/O más lento que el error. Solución: registro muestreado en INFO/WARN. pytest --pdben ejecución paralela con xdist - los trabajadores se conectan de forma confusa. Solución:-n0al depurar.- Optimización de variables bajo
-O-asserty algunas rutas de depuración se eliminan. Solución: no confiar en assert para validación en producción.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
ipdb | querer características de IPython | imágenes CI mínimas sin dependencia |
pudb | TUI a pantalla completa | servidores sin cabeza |
rastros de sentry | agregación de errores en producción | paso a través de locales |
rastros de OpenTelemetry | latencia entre servicios | errores de lógica a nivel de línea |
Preguntas frecuentes
¿Cuál es la diferencia entre pdb y ipdb?
pdb es parte de la biblioteca estándar. ipdb lo envuelve con autocompletado de IPython y mejores tracebacks. Instale ipdb solo en el grupo de dependencias de desarrollo.
¿Cómo uso breakpoint() en FastAPI?
Establezca PYTHONBREAKPOINT=ipdb.set_trace en desarrollo. Un solo trabajador (uvicorn --reload) evita la confusión de múltiples procesos. Nunca en imágenes de producción.
¿Cuándo debo usar logging en lugar de pdb?
Producción, staging bajo carga, y cualquier defecto que no pueda reproducir localmente. Los registros conservan la evidencia después de que el proceso continúa.
¿Cómo funciona pytest --pdb?
En caso de fallo de prueba, pytest abre el modo post-mortem en el frame de la excepción. Combine con -x para detenerse en el primer fallo.
¿Puedo depurar código asyncio?
Sí, con breakpoint() en corrutinas cuando el bucle se ejecuta bajo un solo trabajador. Para casos complejos, use el modo de depuración de asyncio (PYTHONASYNCIODEBUG=1).
¿Cómo adjunto VS Code con debugpy?
Agregue un debugpy.listen(("127.0.0.1", 5678)) y debugpy.wait_for_client() protegidos solo en staging; reenvíe el puerto a través de SSH.
¿Qué es PYTHONBREAKPOINT=0?
Deshabilita las llamadas a breakpoint() - útil en puntos de entrada de producción para evitar que confirmaciones accidentales detengan los despliegues.
¿Debo usar print en bibliotecas?
No. Las bibliotecas registran usando logging.getLogger(__name__). Las aplicaciones configuran manejadores y niveles.
¿Cómo registro en formato JSON?
Use python-json-logger o structlog en aplicaciones; incluya request_id, hash del ID de usuario y tipo de error, no contraseñas en texto plano.
¿Django 5.2 cambia la depuración?
django-debug-toolbar sigue siendo solo para desarrollo. Use la configuración de registro de Django; nunca exponga la barra de herramientas en la configuración de producción.
¿Cómo depuro tareas de Celery?
celery worker --loglevel=INFO más IDs de tarea en los registros. Reproduzca de forma ansiosa con task.apply() en la shell antes de la conexión remota.
¿Cuándo es suficiente faulthandler?
Cuando los procesos se bloquean sin excepciones: interbloqueo o bloqueo de extensión C. SIGUSR1 puede activar un volcado de pila si está configurado.
Relacionados
- Errores de argumentos predeterminados mutables - inspeccionar con pdb
- Interbloqueos de asyncio y bloqueo del bucle - modo de depuración de asyncio
- Escenarios de fugas de memoria - compañero de tracemalloc
- Conflictos de dependencias y entorno - verificar intérprete en pdb
- Fragmentos de refactorización de depuración - correcciones después de encontrar la causa raíz
Versiones de la pila: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.