Estoy escribiendo una aplicación Python que toma como comando como argumento, por ejemplo:
$ python myapp.py command1
Quiero que la aplicación sea extensible, es decir, que pueda agregar nuevos módulos que implementen nuevos comandos sin tener que cambiar la fuente principal de la aplicación. El árbol se parece a:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Entonces, quiero que la aplicación encuentre los módulos de comando disponibles en tiempo de ejecución y ejecute el apropiado.
Python define una función __import__ , que toma una cadena para el nombre de un módulo:
__importar __ (nombre, globales = Ninguno, locales = Ninguno, de la lista = (), nivel = 0)
La función importa el nombre del módulo, potencialmente usando los globales y locales dados para determinar cómo interpretar el nombre en un contexto de paquete. La lista de origen proporciona los nombres de los objetos o submódulos que deben importarse del módulo dado por su nombre.
Fuente: https://docs.python.org/3/library/functions.html# import
Así que actualmente tengo 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()
Esto funciona bien, solo me pregunto si es posible que haya una forma más idiomática de lograr lo que estamos haciendo con este código.
Tenga en cuenta que específicamente no quiero usar huevos o puntos de extensión. Este no es un proyecto de código abierto y no espero que haya "complementos". El objetivo es simplificar el código de la aplicación principal y eliminar la necesidad de modificarlo cada vez que se agrega un nuevo módulo de comando.
fuente
dir(__import__)
. La lista from from debe ser una lista de nombres para emular "from name import ...".importlib
: stackoverflow.com/a/54956419/687896Respuestas:
Con Python anterior a 2.7 / 3.1, así es como lo haces.
Para las versiones más recientes, ver
importlib.import_module
para Python 2 y y Python 3 .Puedes usar
exec
si quieres también.O utilizando
__import__
puede importar una lista de módulos haciendo esto:Ripeado directamente de Dive Into Python .
fuente
__init__
ese módulo?__import__
. Los documentos 2.7: "Debido a que esta función está destinada para el intérprete de Python y no para uso general, es mejor usar importlib.import_module () ..." Al usar python3, elimp
módulo resuelve este problema, como se menciona a continuación en monkut.foreach
cuando tienesfor element in
ymap()
aunque :)La forma recomendada para Python 2.7 y 3.1 y posterior es usar el
importlib
módulo:p.ej
fuente
__import__
función a favor del módulo mencionado anteriormente.os.path
; ¿qué talfrom os.path import *
?globals().update(my_module.__dict)
Como se mencionó, el módulo imp le proporciona funciones de carga:
Los he usado antes para realizar algo similar.
En mi caso, definí una clase específica con los métodos definidos que se requerían. Una vez que cargué el módulo, verificaría si la clase estaba en el módulo y luego crearía una instancia de esa clase, algo como esto:
fuente
expected_class
lo que podría hacer en suclass_inst = getattr(py_mod,expected_name)()
lugar.Use el módulo imp , o la
__import__()
función más directa .fuente
Hoy en día deberías usar importlib .
Importar un archivo fuente
Los documentos realmente proporcionan una receta para eso, y dice así:
De esta forma puede acceder a los miembros (por ejemplo, una función "
hello
") desde su módulopluginX.py
, en este fragmento que se llamamodule
, bajo su espacio de nombres; Ejmodule.hello()
.Si desea importar los miembros (por ejemplo, "
hello
") puede incluirmodule
/pluginX
en la lista de módulos en memoria:Importar un paquete
Importar un paquete ( por ejemplo ,
pluginX/__init__.py
) bajo su directorio actual es realmente sencillo:fuente
sys.modules[module_name] = module
al final de su código si desea poderimport module_name
despuésSi lo quieres en tus locales:
lo mismo funcionaría con
globals()
fuente
locals()
función incorporada advierte explícitamente que "el contenido de este diccionario no debe modificarse".Puedes usar
exec
:fuente
as command_module
al final de la declaración de importación y luego hagacommand_module.run()
Similar a la solución de @monkut pero reutilizable y tolerante a errores descrita aquí http://stamat.wordpress.com/dynamic-module-import-in-python/ :
fuente
La siguiente pieza funcionó para mí:
si desea importar en shell-script:
fuente
Por ejemplo, los nombres de mis módulos son como
jan_module
/feb_module
/mar_module
.fuente
Lo siguiente funcionó para mí:
Carga módulos de la carpeta 'modus'. Los módulos tienen una sola clase con el mismo nombre que el nombre del módulo. Por ejemplo, el archivo modus / module1.py contiene:
El resultado es una lista de clases cargadas dinámicamente "adaptadores".
fuente
fl
? La definición del bucle for es demasiado compleja. El camino está codificado (y, por ejemplo, es irrelevante). Está utilizando python desalentado (__import__
), ¿para qué sirve todo esofl[i]
? Esto es básicamente ilegible, y es innecesariamente complejo para algo que no es tan difícil: vea la respuesta más votada con su frase.