importar módulo desde variable de cadena

183

Estoy trabajando en una documentación (personal) para la biblioteca matplotlib anidada (MPL), que difiere de la propia MPL proporcionada, por paquetes de submódulos interesados. Estoy escribiendo un script Python que espero automatice la generación de documentos a partir de futuras versiones de MPL.
Seleccioné submódulos / paquetes interesados ​​y quiero enumerar sus clases principales a partir de las cuales generaré una lista y la procesaré conpydoc

El problema es que no puedo encontrar una manera de indicarle a Python que cargue el submódulo de la cadena. Aquí hay un ejemplo de lo que probé:

import matplotlib.text as text
x = dir(text)

.

i = __import__('matplotlib.text')
y = dir(i)

.

j = __import__('matplotlib')
z = dir(j)

Y aquí hay una comparación de 3 vías de las listas anteriores a través de pprint:

ingrese la descripción de la imagen aquí

No entiendo lo que está cargado en el yobjeto: es base matplotlibmás algo más, pero carece de la información que quería y esas son las clases principales del matplotlib.textpaquete. Es la parte superior de color azul en la captura de pantalla ( xlista)

No sugiera a Sphinx como un enfoque diferente.

theta
fuente
¿Puede explicar por qué necesita usar en __import__(str)lugar del estado estándar import?
thesamet
Es porque procesaré las listas de los elementos que son submódulos MPL y obtendré sus rutas de métodos
theta
9
@thesamet - vamos - hay un sinfín de ideas donde querrías esta funcionalidad. Cuando tiene una configuración textual de bibliotecas, puede cargarlas por nombre, lo que no funcionaría con la importdeclaración. Aquí hay un ejemplo de uso: djangosnippets.org/snippets/3048
Tomasz Gandor

Respuestas:

279

La __import__función puede ser un poco difícil de entender.

Si cambias

i = __import__('matplotlib.text')

a

i = __import__('matplotlib.text', fromlist=[''])

entonces ise referirá a matplotlib.text.

En Python 2.7 y Python 3.1 o posterior, puede usar importlib:

import importlib

i = importlib.import_module("matplotlib.text")

Algunas notas

  • Si está intentando importar algo de una subcarpeta, por ejemplo ./feature/email.py, el código se verá asíimportlib.import_module("feature.email")

  • No puede importar nada si no hay __init__.pyen la carpeta con el archivo que está intentando importar

mzjn
fuente
3
importlibdebería estar disponible en pypi para <python2.7
Jeffrey Jose
50
Para cualquiera que venga de Google. Cabe señalar que si está intentando importar algo de una subcarpeta (por ejemplo ./feature/email.py) , el código se verá asíimportlib.import_module("feature.email")
Seanny123
11
Finalmente, recuerde también que no puede importar nada si no hay __init__.pyen la carpeta con el archivo que está intentando importar.
Seanny123
3
@mzjn Esto es para import moduleNamedonde moduleName es una cadena. ¿Qué tal from moduleName import *?
Nam G VU
2
Acabo de encontrar la respuesta a mi pregunta aquí en caso de que alguien la necesite stackoverflow.com/a/31306598/248616
Nam G VU
68

importlib.import_modulees lo que buscas. Devuelve el módulo importado. (Solo disponible para Python> = 2.7 o 3.x):

import importlib

mymodule = importlib.import_module('matplotlib.text')

A partir de entonces, puede acceder a cualquier cosa en el módulo como mymodule.myclass, etc.

gecco
fuente
Una alternativa es imp.load_source(..)usar el impmódulo como se sugiere en esta respuesta stackoverflow.com/questions/67631/…
Evgeni Sergeev
55
@gecco Esto es para import moduleNamedonde moduleName es una cadena. ¿Qué tal from moduleName import *?
Nam G VU
6

pasé algún tiempo tratando de importar módulos de una lista, y este es el hilo que me llevó casi todo el camino, pero no comprendí el uso de ___import____ -

Así que aquí se explica cómo importar un módulo desde una cadena y obtener el mismo comportamiento que solo importar. Y pruebe / excepto el caso de error, también. :)

  pipmodules = ['pycurl', 'ansible', 'bad_module_no_beer']
  for module in pipmodules:
      try:
          # because we want to import using a variable, do it this way
          module_obj = __import__(module)
          # create a global object containging our module
          globals()[module] = module_obj
      except ImportError:
          sys.stderr.write("ERROR: missing python module: " + module + "\n")
          sys.exit(1)

y sí, para python 2.7> tiene otras opciones, pero para 2.6 <, esto funciona.

afilado
fuente
1

Desarrollé estas 3 funciones útiles:

def loadModule(moduleName):
    module = None
    try:
        import sys
        del sys.modules[moduleName]
    except BaseException as err:
        pass
    try:
        import importlib
        module = importlib.import_module(moduleName)
    except BaseException as err:
        serr = str(err)
        print("Error to load the module '" + moduleName + "': " + serr)
    return module

def reloadModule(moduleName):
    module = loadModule(moduleName)
    moduleName, modulePath = str(module).replace("' from '", "||").replace("<module '", '').replace("'>", '').split("||")
    if (modulePath.endswith(".pyc")):
        import os
        os.remove(modulePath)
        module = loadModule(moduleName)
    return module

def getInstance(moduleName, param1, param2, param3):
    module = reloadModule(moduleName)
    instance = eval("module." + moduleName + "(param1, param2, param3)")
    return instance

Y cada vez que quiero volver a cargar una nueva instancia solo tengo que llamar a getInstance () de esta manera:

myInstance = getInstance("MyModule", myParam1, myParam2, myParam3)

Finalmente puedo llamar a todas las funciones dentro de la nueva instancia:

myInstance.aFunction()

La única especificidad aquí es personalizar la lista de parámetros (param1, param2, param3) de su instancia.

prossblad
fuente
1

Además de usar importlibuno, también puede usar el execmétodo para importar un módulo desde una variable de cadena.

Aquí estoy mostrando un ejemplo de importación del combinationsmétodo desde el itertoolspaquete usando el execmétodo:

MODULES = [
    ['itertools','combinations'],
]

for ITEM in MODULES:
    import_str = "from {0} import {1}".format(ITEM[0],', '.join(str(i) for i in ITEM[1:]))
    exec(import_str)

ar = list(combinations([1, 2, 3, 4], 2))
for elements in ar:
    print(elements)

Salida:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
arsho
fuente