color python python-import

python - color - plotly title



¿Cómo importar un módulo dado su nombre? (11)

Estoy escribiendo una aplicación de 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 ve algo así como:

myapp/ __init__.py commands/ __init__.py command1.py command2.py foo.py bar.py

Así que 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 un nombre de módulo:

__importar__ (nombre, globales = Ninguno, locales = Ninguno, fromlist = (), nivel = 0)

La función importa el nombre del módulo, utilizando potencialmente los globales y locales dados para determinar cómo interpretar el nombre en el contexto de un paquete. La lista de origen proporciona los nombres de objetos o submódulos que deben importarse del módulo dado por 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, me pregunto si existe posiblemente una forma más idiomática de lograr lo que estamos haciendo con este código.

Tenga en cuenta que específicamente no quiero entrar al uso de huevos o puntos de extensión. Este no es un proyecto de código abierto y no espero que haya "complementos". El punto es simplificar el código principal de la aplicación y eliminar la necesidad de modificarlo cada vez que se agregue un nuevo módulo de comando.


Nota: imp está en desuso desde Python 3.4 a favor de importlib

Como se mencionó anteriormente, el módulo imp proporciona funciones de carga:

imp.load_source(name, path) imp.load_compiled(name, path)

He usado estos antes para realizar algo similar.

En mi caso, definí una clase específica con métodos definidos que eran necesarios. 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:

import imp import os def load_from_file(filepath): class_inst = None expected_class = ''MyClass'' mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) if file_ext.lower() == ''.py'': py_mod = imp.load_source(mod_name, filepath) elif file_ext.lower() == ''.pyc'': py_mod = imp.load_compiled(mod_name, filepath) if hasattr(py_mod, expected_class): class_inst = getattr(py_mod, expected_class)() return class_inst


Con Python anterior a 2.7 / 3.1, así es como lo haces.

Para versiones más recientes, vea importlib.import_module para Python 2 y Python 3 .

Puedes usar exec si quieres también.

O usando __import__ puedes importar una lista de módulos haciendo esto:

>>> moduleNames = [''sys'', ''os'', ''re'', ''unittest''] >>> moduleNames [''sys'', ''os'', ''re'', ''unittest''] >>> modules = map(__import__, moduleNames)

Arrancado directamente de Dive Into Python .


La forma recomendada para Python 2.7 y 3.1 y posteriores es usar el módulo importlib :

importlib.import_module (nombre, paquete = Ninguno)

Importar un módulo. El argumento de nombre especifica qué módulo se va a importar en términos absolutos o relativos (por ejemplo, pkg.mod o ..mod). Si el nombre se especifica en términos relativos, entonces el argumento del paquete debe establecerse en el nombre del paquete que debe actuar como el ancla para resolver el nombre del paquete (por ejemplo, import_module (''.. mod'', ''pkg.subpkg'') importará pkg.mod).

p.ej

my_module = importlib.import_module(''os.path'')


La siguiente pieza funcionó para mí:

>>>import imp; >>>fp, pathname, description = imp.find_module("/home/test_module"); >>>test_module = imp.load_module("test_module", fp, pathname, description); >>>print test_module.print_hello();

Si quieres importar en shell-script:

python -c ''<above entire code in one line>''


Lo siguiente me funcionó:

import sys, glob sys.path.append(''/home/marc/python/importtest/modus'') fl = glob.glob(''modus/*.py'') modulist = [] adapters=[] for i in range(len(fl)): fl[i] = fl[i].split(''/'')[1] fl[i] = fl[i][0:(len(fl[i])-3)] modulist.append(getattr(__import__(fl[i]),fl[i])) adapters.append(modulist[i]())

Carga módulos desde 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 / modu1.py contiene:

class modu1(): def __init__(self): self.x=1 print self.x

El resultado es una lista de clases "adaptadores" cargadas dinámicamente.


Parece que lo que realmente quieres es una arquitectura de plugin.

Debería echar un vistazo a la funcionalidad de puntos de entrada que proporciona el paquete setuptools. Ofrece una excelente manera de descubrir complementos que se cargan para su aplicación.


Puedes usar exec :

exec "import myapp.commands.%s" % command


Si lo quieres en tus locales:

>>> mod = ''sys'' >>> locals()[''my_module''] = __import__(mod) >>> my_module.version ''2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]''

Lo mismo funcionaría con globals()


Similar a la solución de @monkut pero reutilizable y tolerante a errores, se describe aquí stamat.wordpress.com/dynamic-module-import-in-python :

import os import imp def importFromURI(uri, absl): mod = None if not absl: uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri)) path, fname = os.path.split(uri) mname, ext = os.path.splitext(fname) if os.path.exists(os.path.join(path,mname)+''.pyc''): try: return imp.load_compiled(mname, uri) except: pass if os.path.exists(os.path.join(path,mname)+''.py''): try: return imp.load_source(mname, uri) except: pass return mod



por ejemplo: los nombres de mis módulos son como jan_module / feb_module / mar_module

mes = ''feb''
exec ''de% s_module import *''% (month)