importlib — Mecanismo de importación de Python

Propósito:El módulo importlib expone la implementación de la declaración de importación de Python.

El módulo importlib incluye funciones que implementan el mecanismo de importación de Python para cargar código en paquetes y módulos. Es un punto de acceso para importar módulos dinámicamente, y es útil en algunos casos donde el nombre del módulo que debe importarse es desconocido cuando se escribe el código (por ejemplo, para complementos o extensiones de una aplicación).

Paquete de ejemplo

Los ejemplos en esta sección usan un paquete llamado example con __init__.py.

example/__init__.py
print('Importing example package')

El paquete también contiene submodule.py.

example/submodule.py
print('Importing submodule')

Está atento al texto de las llamadas print() en la salida de muestra cuando se importa el paquete o el módulo.

Tipos de modulo

Python admite varios estilos de módulos. Cada uno requiere su propio manejo al abrir el módulo y agregarlo al espacio de nombres, y el soporte para los formatos varía según la plataforma. Por ejemplo, en Microsoft Windows, las bibliotecas compartidas se cargan desde archivos con extensiones .dll o .pyd, en lugar de .so. Las extensiones para los módulos C también pueden cambiar cuando se utiliza una compilación de depuración del intérprete en lugar de una compilación de lanzamiento normal, ya que también se pueden compilar con información de depuración incluida. Si una biblioteca de extensión C u otro módulo no se carga como se esperaba, usa las constantes definidas en importlib.machinery para encontrar los tipos admitidos para la plataforma actual y los parámetros para cargarlos.

importlib_suffixes.py
import importlib.machinery

SUFFIXES = [
    ('Source:', importlib.machinery.SOURCE_SUFFIXES),
    ('Debug:',
     importlib.machinery.DEBUG_BYTECODE_SUFFIXES),
    ('Optimized:',
     importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES),
    ('Bytecode:', importlib.machinery.BYTECODE_SUFFIXES),
    ('Extension:', importlib.machinery.EXTENSION_SUFFIXES),
]


def main():
    tmpl = '{:<10}  {}'
    for name, value in SUFFIXES:
        print(tmpl.format(name, value))


if __name__ == '__main__':
    main()

El valor de retorno es una secuencia de tuplas que contienen la extensión del archivo, el modo a utilizar para abrir el archivo que contiene el módulo y un código de tipo de una constante definida en el módulo. Esta tabla está incompleta, porque algunos de los tipos de módulos o paquetes importables no corresponden a archivos individuales.

$ python3 importlib_suffixes.py

Source:     ['.py']
Debug:      ['.pyc']
Optimized:  ['.pyc']
Bytecode:   ['.pyc']
Extension:  ['.cpython-36m-darwin.so', '.abi3.so', '.so']

Importar Módulos

La interfaz de programación de alto nivel en importlib simplifica la importación de un módulo con un nombre absoluto o relativo. Cuando utilizas un nombre de módulo relativo, especifica el paquete que contiene el módulo como un argumento separado.

importlib_import_module.py
import importlib


m1 = importlib.import_module('example.submodule')
print(m1)

m2 = importlib.import_module('.submodule', package='example')
print(m2)

print(m1 is m2)

El valor de retorno de import_module() es el objeto del módulo creado por la importación.

$ python3 importlib_import_module.py

Importing example package
Importing submodule
<module 'example.submodule' from '.../example/submodule.py'>
<module 'example.submodule' from '.../example/submodule.py'>
True

Si el módulo no se puede importar, import_module() genera ImportError.

importlib_import_module_error.py
import importlib


try:
    importlib.import_module('example.nosuchmodule')
except ImportError as err:
    print('Error:', err)

El mensaje de error incluye el nombre del módulo que falta.

$ python3 importlib_import_module_error.py

Importing example package
Error: No module named 'example.nosuchmodule'

Para volver a cargar un módulo existente, usa reload().

importlib_reload.py
import importlib


m1 = importlib.import_module('example.submodule')
print(m1)

m2 = importlib.reload(m1)
print(m1 is m2)

El valor de retorno de reload() es el nuevo módulo. Dependiendo del tipo de cargador utilizado, puede ser la misma instancia de módulo.

$ python3 importlib_reload.py

Importing example package
Importing submodule
<module 'example.submodule' from '.../example/submodule.py'>
Importing submodule
True

Cargadores

La interfaz de programación de nivel inferior en importlib proporciona acceso a los objetos del cargador, como se describe en Módulos e Importaciones de la sección sobre el módulo sys. Para obtener un cargador para un módulo, usa find_loader(). Luego, para recuperar el módulo, usa el método load_module() del cargador.

importlib_find_loader.py
import importlib

loader = importlib.find_loader('example')
print('Loader:', loader)

m = loader.load_module()
print('Module:', m)

Este ejemplo carga el nivel superior del paquete example.

$ python3 importlib_find_loader.py

Loader: <_frozen_importlib_external.SourceFileLoader object at
0x101fe1828>
Importing example package
Module: <module 'example' from '.../example/__init__.py'>

Los submódulos dentro de los paquetes deben cargarse por separado utilizando la ruta del paquete. En el siguiente ejemplo, el paquete se carga primero y luego su ruta se pasa a find_loader() para crear un cargador capaz de cargar el submódulo.

importlib_submodule.py
import importlib

pkg_loader = importlib.find_loader('example')
pkg = pkg_loader.load_module()

loader = importlib.find_loader('submodule', pkg.__path__)
print('Loader:', loader)

m = loader.load_module()
print('Module:', m)

A diferencia de import_module(), el nombre del submódulo debe darse sin ningún prefijo de ruta relativo, ya que el cargador ya estará limitado por la ruta del paquete.

$ python3 importlib_submodule.py

Importing example package
Loader: <_frozen_importlib_external.SourceFileLoader object at
0x101fe1f28>
Importing submodule
Module: <module 'submodule' from '.../example/submodule.py'>

Ver también