Я пишу приложение на Python, которое принимает в качестве аргумента команду, например:
$ python myapp.py command1
Я хочу, чтобы приложение было расширяемым, то есть позволяло добавлять новые модули, реализующие новые команды, без необходимости изменения основного источника приложения. Дерево выглядит примерно так:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Поэтому я хочу, чтобы приложение находило доступные командные модули во время выполнения и выполняло соответствующий.
Python определяет функцию __import__ , которая принимает строку для имени модуля:
__import __ (name, globals = None, localals = None, fromlist = (), level = 0)
Функция импортирует имя модуля, потенциально используя заданные глобальные и локальные значения, чтобы определить, как интерпретировать имя в контексте пакета. Список from дает имена объектов или подмодулей, которые должны быть импортированы из модуля, заданного именем.
Источник: https://docs.python.org/3/library/functions.html# import
Так что в настоящее время у меня есть что-то вроде:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Это прекрасно работает, мне просто интересно, есть ли более идиоматический способ выполнить то, что мы делаем с этим кодом.
Обратите внимание, что я специально не хочу использовать яйца или точки расширения. Это не проект с открытым исходным кодом, и я не ожидаю, что будут "плагины". Смысл в том, чтобы упростить основной код приложения и избавить от необходимости изменять его каждый раз, когда добавляется новый командный модуль.
источник
dir(__import__)
. Список должен быть списком имен для эмуляции "из импорта имен ...".importlib
: stackoverflow.com/a/54956419/687896Ответы:
С Python старше 2.7 / 3.1 это в значительной степени то, как вы это делаете.
Для более новых версий см.
importlib.import_module
Для Python 2 и и Python 3 .Вы также можете использовать,
exec
если хотите.Или используя
__import__
вы можете импортировать список модулей, выполнив это:Разорвал прямо из Dive Into Python .
источник
__init__
этот модуль?__import__
. Документы 2.7: «Поскольку эта функция предназначена для использования интерпретатором Python, а не для общего использования, лучше использовать importlib.import_module () ...» При использовании python3imp
модуль решает эту проблему, как упоминается ниже в monkut.foreach
когда естьfor element in
иmap()
хоть :)Рекомендуемый способ для Python 2.7 и 3.1 и выше - использовать
importlib
модуль:например
источник
__import__
функции в пользу упомянутого выше модуля.os.path
; как насчетfrom os.path import *
?globals().update(my_module.__dict)
Как уже упоминалось, модуль Imp предоставляет вам функции загрузки:
Я использовал их раньше, чтобы выполнить нечто подобное.
В моем случае я определил определенный класс с определенными необходимыми методами. Как только я загрузил модуль, я бы проверил, есть ли класс в модуле, а затем создал бы экземпляр этого класса, что-то вроде этого:
источник
expected_class
так что вы могли бы сделатьclass_inst = getattr(py_mod,expected_name)()
вместо этого.Используйте модуль imp или более прямую
__import__()
функцию.источник
В настоящее время вы должны использовать importlib .
Импортировать исходный файл
В документах на самом деле обеспечивают рецепт для этого, и он идет , как:
Таким образом, вы можете получить доступ к членам (например, функции "
hello
") из вашего модуляpluginX.py
- в этом вызываемом фрагментеmodule
- из его пространства имен; Например,module.hello()
.Если вы хотите импортировать элементы (например, "
hello
"), вы можете включитьmodule
/pluginX
в список модулей в памяти:Импортировать пакет
Импортировать пакет ( например ,
pluginX/__init__.py
) под текущим каталогом на самом деле просто:источник
sys.modules[module_name] = module
в конец своего кода, если вы хотите иметь возможностьimport module_name
впоследствииЕсли вы хотите это в ваших местных жителей:
то же самое будет работать с
globals()
источник
locals()
функции явно предупреждает , что «содержание этого словаря не должно быть изменено».Вы можете использовать
exec
:источник
as command_module
в конец оператора import, а затем сделатьcommand_module.run()
Аналогично решению @monkut, но его можно использовать повторно и допускать ошибки, описанные здесь http://stamat.wordpress.com/dynamic-module-import-in-python/ :
источник
Следующая часть работала для меня:
если вы хотите импортировать в shell-скрипт:
источник
Например, мои имена модулей похожи на
jan_module
/feb_module
/mar_module
.источник
Следующее работало для меня:
Загружает модули из папки 'modus'. Модули имеют один класс с тем же именем, что и имя модуля. Например, файл modus / modu1.py содержит:
В результате получается список динамически загружаемых классов «адаптеров».
источник
fl
? Определение цикла for является слишком сложным. Путь жестко запрограммирован (и, например, не имеет значения). Он использует обескураженный python (__import__
), для чего все этоfl[i]
? Это в основном нечитаемо и неоправданно сложно для чего-то, что не так уж сложно - посмотрите на голосующий ответ с одной строкой.