импортировать модуль из строковой переменной

183

Я работаю над документацией (личной) для библиотеки nested matplotlib (MPL), которая отличается от собственной MPL интересными пакетами подмодулей. Я пишу скрипт на Python, который, я надеюсь, автоматизирует генерацию документов из будущих выпусков MPL.
Я выбрал заинтересованные подмодули / пакеты и хочу перечислить их основные классы, из которых я сгенерирую список и обработаю егоpydoc

Проблема в том, что я не могу найти способ указать Python загрузить субмодуль из строки. Вот пример того, что я пробовал:

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

,

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

,

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

А вот 3 способа сравнения вышеперечисленных списков через pprint:

введите описание изображения здесь

Я не понимаю, что загружено в yобъект - это база matplotlibплюс что-то еще, но в ней отсутствует информация, которую я хотел, и это основные классы из matplotlib.textпакета. Это верхняя синяя часть на скриншоте ( xсписок)

Пожалуйста, не предлагайте Сфинксу другой подход.

тета
источник
Можете ли вы объяснить, почему вы должны использовать, __import__(str)а не стандартный importStatemetn?
TheSamet
Это потому, что я обработаю списки, какие элементы являются подмодулями MPL, и получу пути их методов
theta
9
@thesamet - давай - есть бесконечные идеи, где вы хотели бы эту функциональность. Когда у вас есть текстовая конфигурация библиотек, вы можете загрузить их по имени, что не совсем подходит для importоператора. Вот один из примеров использования: djangosnippets.org/snippets/3048
Томаш Гандор

Ответы:

279

__import__Функция может быть немного трудно понять.

Если вы измените

i = __import__('matplotlib.text')

в

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

тогда iбудет ссылаться на matplotlib.text.

В Python 2.7 и Python 3.1 или более поздней версии вы можете использовать importlib:

import importlib

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

Некоторые заметки

  • Если вы пытаетесь импортировать что-то из подпапки, например ./feature/email.py, код будет выглядетьimportlib.import_module("feature.email")

  • Вы ничего не можете импортировать, если __init__.pyв папке с файлом, который вы пытаетесь импортировать, ничего нет

mzjn
источник
3
importlibдолжен быть доступен на pypi для <python2.7
Джеффри Хосе
50
Для тех, кто приходит сюда из Google. Следует отметить, что если вы пытаетесь импортировать что-либо из ./feature/email.pyimportlib.import_module("feature.email")
подпапки
11
Наконец, помните, что вы ничего не можете импортировать, если __init__.pyв папке с файлом, который вы пытаетесь импортировать, ничего нет .
Seanny123
3
@mzjn Это для import moduleNameгде moduleName является строкой. Как насчет from moduleName import *?
Нам G VU
2
Только что нашел ответ на мой вопрос здесь на тот случай, если кому-то понадобится это stackoverflow.com/a/31306598/248616
Nam G VU
68

importlib.import_moduleэто то, что вы ищете. Возвращает импортированный модуль. (Доступно только для Python> = 2.7 или 3.x):

import importlib

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

После этого вы можете получить доступ к чему-либо в модуле, как mymodule.myclassи т. Д.

GECCO
источник
В качестве альтернативы можно imp.load_source(..)использовать impмодуль, предложенный в этом ответе stackoverflow.com/questions/67631/…
Евгений Сергеев
5
@gecco Это для import moduleNameгде moduleName является строкой. Как насчет from moduleName import *?
Нам Г ВУ
6

потратил некоторое время, пытаясь импортировать модули из списка, и это поток, который помог мне пройти большую часть пути - но я не понял использование ___import____ -

так вот, как импортировать модуль из строки и получить то же поведение, что и при импорте. И попробуйте / кроме случая ошибки тоже. :)

  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)

и да, для python 2.7> у вас есть другие варианты - но для 2.6 <это работает.

острому
источник
1

Я разработал эти 3 полезные функции:

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

И каждый раз, когда я хочу перезагрузить новый экземпляр, мне просто нужно вызвать getInstance () следующим образом:

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

Наконец, я могу вызвать все функции внутри нового экземпляра:

myInstance.aFunction()

Единственной особенностью здесь является настройка списка параметров (param1, param2, param3) вашего экземпляра.

prossblad
источник
1

Помимо использования importlibможно также использовать execметод для импорта модуля из строковой переменной.

Здесь я показываю пример импорта combinationsметода из itertoolsпакета, используя execметод:

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)

Вывод:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
Arsho
источник