22 · Paquetes: directorios, __init__.py, importaciones relativas
Un paquete es un directorio de módulos. Aprende cómo __init__.py organiza la API pública, cómo funcionan las importaciones absolutas y relativas dentro de un paquete y cómo pip install -e . conecta tu código experimental a Jupyter.
Un **paquete** es un directorio que contiene un archivo `__init__.py` (haciendo que Python lo trate como un espacio de nombres de módulo) más cualquier cantidad de submódulos y subpaquetes. `from mypkg.utils import normalize` permite construir codebases grandes y organizados donde cada preocupación vive en su propio archivo.
Sin esto:
Sin paquetes, todo proyecto de ML es un montón plano de archivos `.py`. Una vez que tienes más de unos pocos, las colisiones de nombres y las importaciones circulares se vuelven inevitables. Los paquetes te dan un espacio de nombres jerárquico: `myproject.data`, `myproject.models.transformer`, `myproject.training`.
Un paquete es un directorio con un archivo __init__.py. Python 3.3+ también soporta namespace packages — directorios sin __init__.py — pero un __init__.py explícito sigue siendo la mejor práctica porque permite controlar qué expone from mypkg import * y da a los lectores una señal clara de que el directorio es un paquete. Los paquetes anidados son simplemente subdirectorios que también tienen __init__.py. Dentro de un paquete, puedes usar importaciones relativas — from .utils import normalize — que son relativas a la posición del módulo actual y sobreviven a los renombrados del paquete. Desde fuera del paquete, usa importaciones absolutas: from mlproject.data import load_dataset. Puedes convertir tu propio paquete en una biblioteca instalable con un pyproject.toml mínimo y pip install -e ., que crea una instalación editable — un enlace simbólico para que tus cambios se reflejen inmediatamente sin reinstalar.
`__init__.py` tiene dos tareas: (1) decirle a Python que este directorio es un paquete, y (2) opcionalmente re-exportar nombres para que los usuarios usen `from mlproject import load_dataset` en lugar del más largo `from mlproject.data import load_dataset`. Mantén `__init__.py` delgado — re-exporta los nombres públicos clave, deja la implementación en los submódulos.
Las importaciones absolutas especifican la ruta completa desde la raíz del paquete. Funcionan desde cualquier lugar en `sys.path` y hacen explícita la estructura de dependencias — un nuevo lector puede ver inmediatamente dónde vive `LinearModel`.
`pyproject.toml` reemplazó al antiguo `setup.py` / `setup.cfg` como la forma estándar de declarar los metadatos y dependencias de un paquete. El campo `requires-python` protege a los usuarios que aún tienen Python 3.9.
¿Cuáles son las dos cosas principales que logra un archivo `__init__.py` (vacío)?
- Un paquete = un directorio + `__init__.py`. Los paquetes anidados son subdirectorios con su propio `__init__.py`. Python 3.3+ permite namespace packages (sin `__init__.py`) pero lo explícito es mejor.
- Desde fuera de un paquete, usa importaciones absolutas: `from mlproject.data import load_dataset`. Desde dentro, prefiere importaciones relativas: `from .utils import normalize`, `from ..data import load_dataset`.
- `pip install -e .` con un `pyproject.toml` crea una instalación editable — tus cambios de fuente son inmediatamente importables en notebooks y otros scripts sin reinstalar.
Todo repositorio de ML reutilizable es un paquete: `import myproject.training`, `import myproject.models.transformer`, `import myproject.data.loaders`. Sin paquetes estás atascado en scripts de un solo archivo que no pueden compartir código sin copiar y pegar. Los repositorios de investigación como HuggingFace Transformers, PyTorch Lightning y FastAI exponen toda su funcionalidad a través de jerarquías de paquetes profundas — `from transformers.models.bert import BertModel`.
Si lo quitas: Sin paquetes, un proyecto con preocupaciones separadas de carga de datos, preprocesamiento, modelado y evaluación necesitaría cada función en un único archivo monolítico — o dependería de hacks frágiles de `sys.path`. Las jerarquías de paquetes son cómo los equipos de ML mantienen codebases que múltiples colaboradores editan simultáneamente.