modulo di importazione dalla variabile stringa


183

Sto lavorando a una documentazione (personale) per la libreria nid matplotlib (MPL), che differisce da quella fornita da MPL, dai pacchetti di moduli interessati. Sto scrivendo lo script Python che spero automatizzerà la generazione di documenti dalle future versioni di MPL.
Ho selezionato sottomoduli / pacchetti interessati e desidero elencare le loro classi principali da cui genererò l'elenco e lo elaboreròpydoc

Il problema è che non riesco a trovare un modo per istruire Python a caricare il sottomodulo dalla stringa. Ecco un esempio di ciò che ho provato:

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

.

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

.

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

Ed ecco un confronto a 3 vie degli elenchi sopra tramite pprint:

inserisci qui la descrizione dell'immagine

Non capisco cosa sia caricato ynell'oggetto: è base matplotlibpiù qualcos'altro, ma manca di informazioni che volevo e che sono le classi principali dal matplotlib.textpacchetto. È la parte in alto di colore blu sullo screenshot ( xelenco)

Per favore, non suggerire Sphinx come approccio diverso.


Puoi spiegare perché è necessario utilizzare __import__(str)anziché il importmetodo di stato standard ?
martedì

È perché elaboro gli elenchi di quali elementi sono sottomoduli MPL e ottengo i loro percorsi dei metodi
theta

9
@thesamet - dai - ci sono infinite idee in cui vorresti questa funzionalità. Quando si dispone di una configurazione testuale di librerie, è possibile caricarle per nome, il che non funzionerebbe perfettamente con l' importistruzione. Ecco un esempio di utilizzo: djangosnippets.org/snippets/3048
Tomasz Gandor

Risposte:


279

La __import__funzione può essere un po 'difficile da capire.

Se cambi

i = __import__('matplotlib.text')

per

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

quindi ifarà riferimento a matplotlib.text.

In Python 2.7 e Python 3.1 o versioni successive, è possibile utilizzare importlib:

import importlib

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

Alcune note

  • Se stai cercando di importare qualcosa da una sottocartella, ad esempio ./feature/email.py, il codice sarà simileimportlib.import_module("feature.email")

  • Non è possibile importare nulla se __init__.pynella cartella non è presente alcun file che si sta tentando di importare


3
importlibdovrebbe essere disponibile su pypi per <python2.7
Jeffrey Jose il

50
Per chiunque venga qui da Google. Va notato che se stai cercando di importare qualcosa da una sottocartella (ad esempio, ./feature/email.py) il codice sarà simileimportlib.import_module("feature.email")
Seanny123

11
Infine, ricorda anche che non puoi importare nulla se __init__.pynella cartella non è presente alcun file che stai tentando di importare.
Seanny123,

3
@mzjn Questo è per import moduleNamedove moduleName è stringa. Che ne dici from moduleName import *?
Nam G VU,

2
Ho appena trovato la risposta alla mia domanda qui nel caso in cui qualcuno ne abbia bisogno stackoverflow.com/a/31306598/248616
Nam G VU

68

importlib.import_moduleè quello che stai cercando. Restituisce il modulo importato. (Disponibile solo per Python> = 2.7 o 3.x):

import importlib

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

Successivamente puoi accedere a qualsiasi cosa nel modulo come mymodule.myclass, ecc.



5
@gecco Questo è per import moduleNamedove moduleName è stringa. Che ne dici from moduleName import *?
Nam G VU,

6

ho trascorso un po 'di tempo a provare a importare moduli da un elenco, e questo è il thread che mi ha portato quasi ovunque - ma non ho capito l'uso di ___import____ -

quindi ecco come importare un modulo da una stringa e ottenere lo stesso comportamento della sola importazione. E prova anche / tranne il caso di errore. :)

  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)

e sì, per Python 2.7> hai altre opzioni - ma per 2.6 <, funziona.


1

Ho sviluppato queste 3 utili funzioni:

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

E ogni volta che voglio ricaricare una nuova istanza, devo solo chiamare getInstance () in questo modo:

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

Finalmente posso chiamare tutte le funzioni all'interno della nuova istanza:

myInstance.aFunction()

L'unica specificità qui è personalizzare l'elenco dei parametri (param1, param2, param3) della tua istanza.


1

Oltre a usare quello importlibsi può anche usare il execmetodo per importare un modulo da una variabile stringa.

Qui sto mostrando un esempio di importazione del combinationsmetodo dal itertoolspacchetto usando il execmetodo:

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)

Produzione:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.