HOWTO · Python

Python importa todos los módulos en un directorio

Este tutorial explica cómo importar todos los módulos en un directorio en Python.

En esta página

Para importar módulos de un mismo directorio, trata ese directorio como un paquete de Python. Si el conjunto de módulos es fijo, enumera las importaciones en el __init__.py del paquete; si sus nombres no se conocen de antemano, puedes descubrirlos e importarlos usando sus nombres cualificados dentro del paquete con importlib.

Importar todos los módulos presentes en un directorio en Python

Un paquete permite organizar módulos relacionados y ofrecer una interfaz cómoda para acceder a ellos. Por ejemplo, el paquete a puede contener x.py, y.py y z.py, junto con __init__.py. Python ejecuta el inicializador al importar el paquete, pero no importa automáticamente los archivos hermanos. Añade allí importaciones explícitas si quieres que esos módulos estén disponibles como atributos del paquete.

El siguiente ejemplo autocontenido crea el paquete, importa sus módulos en el inicializador y accede a cada uno a través de a:

from pathlib import Path
import sys
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temp_dir:
    package_dir = Path(temp_dir) / "a"
    package_dir.mkdir()
    (package_dir / "x.py").write_text("value = 'X'\n", encoding="utf-8")
    (package_dir / "y.py").write_text("value = 'Y'\n", encoding="utf-8")
    (package_dir / "z.py").write_text("value = 'Z'\n", encoding="utf-8")
    (package_dir / "__init__.py").write_text(
        "from . import x, y, z\n", encoding="utf-8"
    )
    sys.path.insert(0, temp_dir)
    try:
        import a
        assert (a.x.value, a.y.value, a.z.value) == ("X", "Y", "Z")
    finally:
        sys.path.remove(temp_dir)
        for module_name in list(sys.modules):
            if module_name == "a" or module_name.startswith("a."):
                sys.modules.pop(module_name, None)

En la ejecución proporcionada y vinculada a esta versión candidata, ambos ejemplos finalizaron correctamente, con código de salida 0 y sin salida estándar.

Las importaciones relativas de __init__.py hacen que los módulos estén disponibles como a.x, a.y y a.z después de import a. Esta lista explícita es fácil de revisar y ofrece al paquete una interfaz predecible. Mantén el inicializador enfocado: importar un paquete ejecuta su inicializador y el código de nivel superior de los módulos importados, así que evita incluir tareas ajenas o efectos secundarios costosos.

Usar importlib para importar módulos de forma avanzada

Si otra parte del programa va añadiendo módulos con el tiempo, quizá no baste con una lista fija de importaciones. La detección compatible con paquetes puede encontrar módulos inmediatos e importarlos por su nombre cualificado. Este ejemplo independiente crea un paquete, detecta sus módulos con pkgutil y guarda cada módulo importado en un diccionario:

from pathlib import Path
import importlib
import pkgutil
import sys
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temp_dir:
    package_dir = Path(temp_dir) / "plugins"
    package_dir.mkdir()
    (package_dir / "__init__.py").write_text("", encoding="utf-8")
    (package_dir / "alpha.py").write_text("value = 1\n", encoding="utf-8")
    (package_dir / "beta.py").write_text("value = 2\n", encoding="utf-8")
    sys.path.insert(0, temp_dir)
    try:
        package = importlib.import_module("plugins")
        modules = {
            item.name: importlib.import_module(f"{package.__name__}.{item.name}")
            for item in pkgutil.iter_modules(package.__path__)
            if not item.ispkg
        }
        assert sorted(modules) == ["alpha", "beta"]
        assert modules["alpha"].value == 1
        assert modules["beta"].value == 2
    finally:
        sys.path.remove(temp_dir)
        for module_name in list(sys.modules):
            if module_name == "plugins" or module_name.startswith("plugins."):
                sys.modules.pop(module_name, None)

Este ejemplo no produce salida estándar:

Usa modules["alpha"] para acceder al objeto de un módulo importado y, después, leer sus atributos o llamar a sus funciones. La detección del ejemplo abarca los módulos inmediatos del paquete y omite los subpaquetes; si también deben cargarse paquetes anidados, cambia esa política de forma deliberada. El ejemplo no aplica un filtro basado en las convenciones de nombres de una aplicación, así que añade un predicado si solo deben cargarse determinados módulos como complementos. La importación ejecuta cada módulo detectado, que podría necesitar dependencias o realizar su propia inicialización. Si falta una dependencia o se produce un error en el código de un módulo, el bucle de carga puede detenerse. La carga dinámica resulta útil cuando el conjunto de módulos puede ampliarse de verdad; si ya conoces los módulos, las importaciones explícitas son más claras y fáciles de mantener. Como las importaciones se ejecutan en el proceso actual, limita la detección al contenido de paquetes de confianza. En paquetes cuya inicialización es costosa, separa el registro de complementos de la carga de módulos y documenta qué nombres pueden usar los llamadores.

Conclusión

Usa importaciones explícitas en __init__.py cuando conozcas los módulos públicos del paquete. Recurre a la detección de módulos compatible con paquetes mediante importlib cuando el programa deba cargar un conjunto que evoluciona, y deja claras para quienes lo usan las reglas de detección y los efectos secundarios de las importaciones.