我如何能导入一个模块动态给定它的名字作为字符串?

我正在编写一个Python应用程序,它将命令作为参数,例如:

$ python myapp.py command1

我希望应用程序是可扩展的,也就是说,能够添加实现新命令的新模块,而不必更改主要应用程序源。这棵树看起来像这样:

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

因此,我希望应用程序在运行时找到可用的命令模块并执行适当的命令模块。

Python定义了一个__import__()函数,它接受一个字符串作为模块名:

# EYZ0

该函数导入模块name,可能会使用给定的globalslocals来确定如何在包上下文中解释该名称。fromlist给出了应该从name给出的模块导入的对象或子模块的名称。

来源:# EYZ0_

所以目前我有这样的东西:

command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message


command_module.run()

这工作得很好,我只是想知道是否有一种更习惯的方式来完成我们用这段代码所做的事情。

注意,我特别不想使用卵或扩展点。这不是一个开源项目,我不期望有“插件”。这样做的目的是简化主要的应用程序代码,并且不需要每次添加新的命令模块时都修改它。


参见: 我如何导入一个模块给定的全路径?< / >

399430 次浏览

你可以使用exec:

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

对于2.7/3.1以上的Python,基本上就是这样做的。

对于更新的版本,请参阅importlib.import_module以获得Python 2Python 3

如果您愿意,也可以使用exec

或者使用__import__你可以导入一个模块列表,这样做:

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

直接抄袭深入了解Python

使用小鬼模块,或者更直接的__import__()函数。

注意:小鬼自Python 3.4起已弃用,取而代之的是importlib

如前所述,小鬼模块提供了加载函数:

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

我以前使用过这些函数来执行类似的操作。

在我的例子中,我定义了一个特定的类,并定义了所需的方法。 一旦我加载了模块,我将检查类是否在模块中,然后创建该类的一个实例,类似于:

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

下面的方法对我很有效:

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]())

它从文件夹“modus”加载模块。模块有一个与模块名相同的类。例如,文件modus/modu1.py包含:

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

结果是一个动态加载类“适配器”的列表。

如果你想在局部函数中使用它:

>>> 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)]'

同样也适用于globals()

Python 2.7和3.1及以后版本的推荐方式是使用importlib模块:

# EYZ2 # EYZ3

导入模块。name参数以绝对或相对的形式指定要导入的模块(例如pkg.mod..mod)。如果名称是相对指定的,那么package参数必须设置为包的名称,作为解析包名的锚(例如import_module('..mod', 'pkg.subpkg')将导入pkg.mod)。

如。

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

类似于@monkut的解决方案,但可重用和容错在这里描述http://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

下面这篇文章对我很有用:

>>>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();

如果你想在shell-script中导入:

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

现在你应该使用importlib

导入源文件

文档实际上提供了一个配方,它是这样的:

import sys
import importlib.util


file_path = 'pluginX.py'
module_name = 'pluginX'


spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)


# check if it's all there..
def bla(mod):
print(dir(mod))
bla(module)

通过这种方式,您可以访问模块pluginX.py中的成员(例如,函数“hello”)——在这个代码片段中被称为module——在它的命名空间下;例如,# EYZ3。

如果你想导入成员(例如,“hello”),你可以在模块的内存列表中包含module/pluginX:

sys.modules[module_name] = module


from pluginX import hello
hello()

导入一个包

在当前目录下导入一个包(如。pluginX/__init__.py)实际上很简单:

import importlib


pkg = importlib.import_module('pluginX')


# check if it's all there..
def bla(mod):
print(dir(mod))
bla(pkg)