Вопрос-Ответ

Importing module from string variable using "__import__" gives different results than a normal import statement

Импорт модуля из строковой переменной с использованием "__import__" дает результаты, отличные от обычной инструкции импорта

Я работаю над документацией (личной) для вложенной библиотеки 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 object - это base matplotlib плюс что-то еще, но в нем отсутствует информация, которую я хотел, и это основные классы из matplotlib.text пакета. Это верхняя часть синего цвета на скриншоте (x список).

Переведено автоматически
Ответ 1

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

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

i = __import__('matplotlib.text')

Для

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

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

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

import importlib

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

Some notes


  • If you're trying to import something from a sub-folder e.g. ./feature/email.py, the code will look like importlib.import_module("feature.email")



  • Before Python 3.3 you could not import anything if there was no __init__.py in the folder with file you were trying to import (see caveats before deciding if you want to keep the file for backward compatibility e.g. with pytest).



Ответ 2

importlib.import_module is what you are looking for. It returns the imported module.

import importlib

# equiv. of your `import matplotlib.text as text`
text = importlib.import_module('matplotlib.text')

You can thereafter access anything in the module as text.myclass, text.myfunction, etc.

Ответ 3

spent some time trying to import modules from a list, and this is the thread that got me most of the way there - but I didnt grasp the use of ___import____ -

so here's how to import a module from a string, and get the same behavior as just import. And try/except the error case, too. :)

  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)

and yes, for python 2.7> you have other options - but for 2.6<, this works.

Ответ 4

Apart from using the importlib one can also use exec method to import a module from a string variable.

Here I am showing an example of importing the combinations method from itertools package using the exec method:

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)

Output:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
python