importuj moduł ze zmiennej tekstowej

183

Pracuję nad dokumentacją (osobistą) dla zagnieżdżonej biblioteki matplotlib (MPL), która różni się od dostarczonej przez siebie MPL, zainteresowanymi pakietami podmodułów. Piszę skrypt Python, który, mam nadzieję, zautomatyzuje generowanie dokumentów z przyszłych wydań MPL.
Wybrałem zainteresowane moduły / pakiety i chcę wymienić ich główne klasy, z których wygeneruję listę i przetworzę jąpydoc

Problem polega na tym, że nie mogę znaleźć sposobu, aby poinstruować Python, aby ładował submoduł z łańcucha. Oto przykład tego, co próbowałem:

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

.

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

.

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

A oto 3-kierunkowe porównanie powyższych list przez pprint:

wprowadź opis zdjęcia tutaj

Nie rozumiem, co jest załadowane w yobiekcie - jest to podstawa matplotlibplus coś jeszcze, ale brakuje mi informacji, których chciałem i to są główne klasy z matplotlib.textpakietu. Jest to niebieska część na zrzucie ekranu ( xlista)

Proszę nie sugerować Sfinksa jako innego podejścia.

theta
źródło
Czy możesz wyjaśnić, dlaczego musisz używać __import__(str)zamiast standardowej importstatystyki?
thesamet
To dlatego, że przetworzę listy, które elementy są podmodułami MPL i uzyskam ścieżki metod
theta
9
@thesamet - no dalej - są nieskończone pomysły na tę funkcję. Gdy masz tekstową konfigurację bibliotek, możesz załadować je według nazwy, co nie do końca działałoby z importinstrukcją. Oto przykład użycia: djangosnippets.org/snippets/3048
Tomasz Gandor

Odpowiedzi:

279

__import__Funkcja może być nieco trudne do zrozumienia.

Jeśli się zmienisz

i = __import__('matplotlib.text')

do

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

wtedy ibędzie odnosić się do matplotlib.text.

W Python 2.7 i Python 3.1 lub nowszy możesz użyć importlib:

import importlib

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

Kilka notatek

  • Jeśli próbujesz np. Zaimportować coś z podfolderu ./feature/email.py, kod będzie wyglądałimportlib.import_module("feature.email")

  • Nie możesz zaimportować niczego, jeśli nie ma __init__.pyw folderze pliku, który próbujesz zaimportować

mzjn
źródło
3
importlibpowinien być dostępny na pypi dla <python2.7
Jeffrey Jose
50
Dla każdego, kto przyjeżdża tutaj z Google. Należy zauważyć, że jeśli próbujesz zaimportować coś z podfolderu (na przykład ./feature/email.py), kod będzie wyglądałimportlib.import_module("feature.email")
Seanny123
11
Na koniec pamiętaj również, że nie możesz zaimportować niczego, jeśli nie ma __init__.pyw folderze pliku, który próbujesz zaimportować.
Seanny123
3
@mzjn To jest, import moduleNamegdy string nazwa_modułu jest ciągiem. Jak o from moduleName import *?
Nam G VU
2
Właśnie znalazłem odpowiedź na moje pytanie tutaj na wypadek, gdyby ktoś go potrzebował stackoverflow.com/a/31306598/248616
Nam G VU
68

importlib.import_modulejest tym, czego szukasz. Zwraca zaimportowany moduł. (Dostępne tylko dla Pythona> = 2.7 lub 3.x):

import importlib

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

Następnie możesz uzyskać dostęp do czegokolwiek w module jako mymodule.myclassitp.

gecco
źródło
Alternatywą jest imp.load_source(..)użycie impmodułu zgodnie z sugestią zawartą w tej odpowiedzi stackoverflow.com/questions/67631/...
Evgeni Sergeev,
5
@gecco To jest, import moduleNamegdzie ciąg nazwa_modułu to. Jak o from moduleName import *?
Nam G VU
6

spędziłem trochę czasu próbując zaimportować moduły z listy, i to jest wątek, który zapewnił mi najwięcej możliwości - ale nie zrozumiałem użycia ___import____ -

więc oto jak zaimportować moduł z łańcucha i uzyskać to samo zachowanie, co po prostu import. I spróbuj / oprócz przypadku błędu. :)

  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)

i tak, dla Pythona 2.7> masz inne opcje - ale dla 2.6 <to działa.

zapalony
źródło
1

Opracowałem 3 przydatne funkcje:

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

I za każdym razem, gdy chcę ponownie załadować nową instancję, muszę wywołać metodę getInstance () w następujący sposób:

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

Wreszcie mogę wywołać wszystkie funkcje w nowej instancji:

myInstance.aFunction()

Jedyną specyficznością tutaj jest dostosowanie listy parametrów (param1, param2, param3) instancji.

prossblad
źródło
1

Oprócz użycia tego importlibmożna również użyć execmetody importowania modułu ze zmiennej łańcuchowej.

Oto przykład importowania combinationsmetody z itertoolspakietu przy użyciu execmetody:

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)

Wynik:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
arsho
źródło