Estou escrevendo um aplicativo Python que usa como comando um argumento, por exemplo:
$ python myapp.py command1
Quero que o aplicativo seja extensível, ou seja, seja capaz de adicionar novos módulos que implementam novos comandos sem precisar alterar a fonte principal do aplicativo. A árvore se parece com:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Então, eu quero que o aplicativo encontre os módulos de comando disponíveis em tempo de execução e execute o apropriado.
Python define uma função __import__ , que recebe uma string para o nome de um módulo:
__import __ (nome, globais = Nenhum, locais = Nenhum, da lista = (), nível = 0)
A função importa o nome do módulo, potencialmente usando os globais e locais fornecidos para determinar como interpretar o nome em um contexto de pacote. A lista from fornece os nomes de objetos ou submódulos que devem ser importados do módulo fornecido pelo nome.
Fonte: https://docs.python.org/3/library/functions.html# import
Então, atualmente, tenho algo como:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Isso funciona muito bem, só estou me perguntando se existe uma maneira mais idiomática de realizar o que estamos fazendo com esse código.
Note que eu especificamente não quero usar ovos ou pontos de extensão. Este não é um projeto de código aberto e não espero que haja "plugins". O objetivo é simplificar o código principal do aplicativo e remover a necessidade de modificá-lo toda vez que um novo módulo de comando é adicionado.
fonte
dir(__import__)
. A lista from from deve ser uma lista de nomes para emular "from name import ...".importlib
: stackoverflow.com/a/54956419/687896Respostas:
Com o Python anterior a 2.7 / 3.1, é assim que você faz.
Para as versões mais recentes, ver
importlib.import_module
para Python 2 e e Python 3 .Você pode usar
exec
se quiser também.Ou
__import__
você pode importar uma lista de módulos fazendo o seguinte:Rasgado direto de Dive Into Python .
fonte
__init__
esse módulo?__import__
. Os documentos 2.7: "Como essa função é para ser usada pelo interpretador Python e não para uso geral, é melhor usar importlib.import_module () ..." Ao usar o python3, oimp
módulo resolve esse problema, como o monkut menciona abaixo.foreach
quando você temfor element in
emap()
embora :)A maneira recomendada para o Python 2.7 e 3.1 e posterior é usar o
importlib
módulo:por exemplo
fonte
__import__
função em favor do módulo acima mencionado.os.path
; que talfrom os.path import *
?globals().update(my_module.__dict)
Como mencionado, o módulo imp fornece funções de carregamento:
Eu usei isso antes para executar algo semelhante.
No meu caso, defini uma classe específica com métodos definidos que eram necessários. Depois de carregar o módulo, verificaria se a classe estava no módulo e criaria uma instância dessa classe, algo como isto:
fonte
expected_class
para que você possa fazê-loclass_inst = getattr(py_mod,expected_name)()
.Use o módulo imp , ou a
__import__()
função mais direta .fonte
Atualmente você deve usar importlib .
Importar um arquivo de origem
Os documentos realmente fornecem uma receita para isso, e é assim:
Dessa forma, você pode acessar os membros (por exemplo, uma função "
hello
") do seu módulopluginX.py
- neste trecho chamadomodule
- sob seu espaço de nome; Por exemplomodule.hello()
,.Se você deseja importar os membros (por exemplo, "
hello
"), você pode incluirmodule
/pluginX
na lista de módulos na memória:Importar um pacote
A importação de um pacote ( por exemplo ,
pluginX/__init__.py
) sob seu diretório atual é realmente simples:fonte
sys.modules[module_name] = module
no final do seu código se você quiserimport module_name
depois #Se você quiser nos locais:
mesmo funcionaria com
globals()
fonte
locals()
função interna adverte explicitamente que "o conteúdo deste dicionário não deve ser modificado".Você pode usar
exec
:fonte
as command_module
ao final da instrução de importação e, em seguida, fazercommand_module.run()
Semelhante à solução da @monkut, mas reutilizável e tolerante a erros descrita aqui http://stamat.wordpress.com/dynamic-module-import-in-python/ :
fonte
A peça abaixo funcionou para mim:
se você deseja importar no shell-script:
fonte
Por exemplo, os nomes dos meus módulos são como
jan_module
/feb_module
/mar_module
.fonte
O seguinte funcionou para mim:
Carrega módulos da pasta 'modus'. Os módulos possuem uma única classe com o mesmo nome que o nome do módulo. Por exemplo, o arquivo modus / modu1.py contém:
O resultado é uma lista de classes "adaptadores" carregados dinamicamente.
fonte
fl
? A definição do loop for é excessivamente complexa. O caminho é codificado permanentemente (e por exemplo, irrelevante). É usando python desanimado (__import__
), para que serve tudo issofl[i]
? Isso é basicamente ilegível e desnecessariamente complexo para algo que não é tão difícil - veja a resposta mais votada com uma única frase.