A medida que un proyecto crece, mantener todas las funciones, clases y constantes en un único archivo se vuelve difícil. Los módulos y paquetes en Python permiten dividir el código en partes pequeñas, relacionadas y reutilizables.
Un módulo suele ser un archivo .py. Un paquete es una carpeta que agrupa módulos relacionados. Esta organización facilita las pruebas, reduce repeticiones y permite que varias personas trabajen en el mismo proyecto sin depender de un script enorme.
Qué es un módulo de Python
Cualquier archivo de Python puede convertirse en un módulo. Imagina un archivo llamado calculator.py:
# calculator.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
PI = 3.14159Otro archivo puede importarlo:
# main.py
import calculator
print(calculator.add(10, 5))
print(calculator.PI)El nombre del módulo es el nombre del archivo sin la extensión. La guía oficial de módulos de Python explica cómo se crean los espacios de nombres y cómo se cargan los archivos importados.
Formas de importar
La forma más clara suele mantener visible el nombre del módulo:
import calculator
result = calculator.add(4, 8)También puedes importar nombres concretos:
from calculator import add, subtract
print(add(4, 8))Los alias son útiles para nombres largos o convencionales:
import calculator as calc
print(calc.subtract(20, 3))Evita from module import *. Esta sintaxis oculta el origen de los nombres y puede sobrescribir variables sin que resulte evidente. La guía de PEP 8 en Python presenta convenciones para imports, nombres y organización.
Cómo encuentra Python los módulos
Cuando Python procesa un import, consulta el proyecto actual, la biblioteca estándar, los paquetes instalados y las rutas registradas en sys.path:
import sys
for folder in sys.path:
print(folder)Un error frecuente consiste en llamar a un archivo propio random.py, json.py o requests.py. Ese archivo puede ocultar la biblioteca real y generar importaciones circulares o atributos ausentes.
Trabajar dentro de un entorno aislado reduce confusiones entre intérpretes. La guía de entornos virtuales con venv explica cómo crear y activar un entorno por proyecto.
Qué es un paquete
Un paquete es una carpeta que contiene módulos relacionados. Una aplicación de tienda podría utilizar esta estructura:
store_app/
├── main.py
└── store/
├── __init__.py
├── products.py
├── orders.py
└── reports.pyEl directorio store es el paquete. Cada archivo de Python es un submódulo:
# store/products.py
def calculate_total(price, quantity):
return price * quantity# main.py
from store.products import calculate_total
print(calculate_total(19.90, 3))La función de __init__.py
El archivo __init__.py identifica un paquete tradicional y puede definir su interfaz pública. Puede quedar vacío o volver a exportar nombres seleccionados:
# store/__init__.py
from .products import calculate_total
__all__ = ["calculate_total"]Después puede utilizarse:
from store import calculate_totalMantén este archivo ligero. Abrir conexiones, leer archivos enormes o ejecutar solicitudes de red durante un import vuelve la aplicación lenta e impredecible.
Imports absolutos y relativos
Un import absoluto parte del paquete principal:
from store.products import calculate_totalUn import relativo utiliza puntos para referirse a módulos cercanos:
# store/reports.py
from .products import calculate_totalLos imports absolutos suelen ser más claros en aplicaciones. Los relativos pueden resultar cómodos dentro de un paquete coherente. Lo importante es mantener un criterio consistente.
__name__ y la ejecución directa
Todo módulo posee una variable __name__. Cuando el archivo se ejecuta directamente, su valor es "__main__". Cuando se importa, contiene el nombre del módulo.
def celsius_to_fahrenheit(value):
return value * 9 / 5 + 32
if __name__ == "__main__":
print(celsius_to_fahrenheit(25))Esta protección impide que el código de demostración se ejecute durante una importación. Los módulos internos también pueden ejecutarse desde la raíz con python -m package.module.
Estructura de un proyecto real
expense_tracker/
├── README.md
├── pyproject.toml
├── src/
│ └── expense_tracker/
│ ├── __init__.py
│ ├── models.py
│ ├── storage.py
│ └── cli.py
└── tests/
├── test_models.py
└── test_storage.pyLa carpeta src evita importar accidentalmente el código directamente desde la raíz. Las pruebas quedan separadas y utilizan el paquete como lo haría un usuario. La guía de Pytest para principiantes muestra cómo organizar y ejecutar pruebas automatizadas.
Módulo, paquete, biblioteca y distribución
- Módulo: archivo importable de Python.
- Paquete: directorio importable con módulos.
- Biblioteca: término general para código reutilizable.
- Distribución: proyecto instalable publicado en un índice de paquetes.
Una distribución puede contener varios paquetes. La guía sobre bibliotecas de Python explica cómo evaluar, instalar e importar dependencias.
Ejemplo práctico de paquete
customer_tools/
├── __init__.py
├── names.py
└── validation.py# customer_tools/names.py
def normalize_name(name):
return " ".join(part.capitalize() for part in name.split())# customer_tools/validation.py
def is_valid_email(email):
return "@" in email and "." in email.rsplit("@", 1)[-1]# customer_tools/__init__.py
from .names import normalize_name
from .validation import is_valid_emailEl paquete ofrece una interfaz pequeña y cada módulo mantiene una sola responsabilidad. La guía de funciones en Python ayuda a diseñar operaciones cohesivas antes de distribuirlas entre archivos.
Evitar imports circulares
Existe un import circular cuando el módulo A importa B y B vuelve a importar A. Python puede encontrar un módulo parcialmente inicializado.
Las soluciones más habituales son mover definiciones compartidas a un tercer módulo, reducir dependencias entre capas o realizar un import local cuando exista una razón específica:
package/
├── common.py
├── users.py
└── orders.pyusers.py y orders.py pueden importar tipos comunes sin depender entre sí.
Rutas y recursos del paquete
No supongas que el terminal siempre se ejecuta desde la misma carpeta. Para rutas del proyecto puedes utilizar pathlib:
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
CONFIG_PATH = BASE_DIR / "config.json"La guía de pathlib en Python explica cómo crear rutas portables y trabajar con archivos sin concatenar separadores manualmente.
Documentar la interfaz pública
Una buena estructura no sustituye la documentación. Añade docstrings a funciones, clases y módulos públicos:
"""Utilities for validating customer records."""
def validate_age(age: int) -> bool:
"""Return True when age is inside the accepted range."""
return 0 <= age <= 130La guía de docstrings en Python explica cómo describir parámetros, retornos y excepciones.
Errores frecuentes
- Ejecutar directamente un archivo interno y romper imports relativos.
- Nombrar un archivo igual que una biblioteca estándar.
- Depender del directorio actual del terminal.
- Crear efectos secundarios durante la importación.
- Dividir el proyecto en demasiados módulos diminutos.
- Permitir dependencias circulares entre capas.
- Exponer todos los detalles internos como API pública.
Buenas prácticas
Usa nombres de módulos en minúsculas, agrupa responsabilidades relacionadas, mantén imports claros, evita trabajo costoso durante la carga, utiliza un entorno virtual y añade pruebas antes de reorganizar un proyecto maduro.
La referencia oficial del sistema de imports describe con detalle la búsqueda, carga y creación de módulos.
Conclusión
Los módulos y paquetes convierten un script creciente en una aplicación mantenible. Empieza moviendo funciones relacionadas a dos o tres archivos, crea una interfaz pública sencilla y organiza las dependencias en una dirección clara. Después añade pruebas, documentación y una configuración de proyecto instalable.






