如何以字符串形式动态导入模块?
- 2024-11-21 08:33:00
- admin 原创
- 6
问题描述:
我正在编写一个以命令作为参数的 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, locals=None, fromlist=(), level=0)
函数导入模块
name
,可能使用给定的globals
和locals
来确定如何在包上下文中解释名称。 给出fromlist
应从 给出的模块导入的对象或子模块的名称name
。来源: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()
这工作得很好,我只是想知道是否有可能有一种更惯用的方法来完成我们用这段代码所做的事情。
请注意,我特别不想使用eggs或扩展点。这不是一个开源项目,我也不指望有“插件”。重点是简化主应用程序代码,并消除每次添加新命令模块时修改它的需要。
另请参阅: 如何根据完整路径动态导入模块?
解决方案 1:
对于 Python 2.7 和 3.1 及更高版本,推荐的方法是使用importlib
模块:
importlib.import_module(
name, package=None)
导入模块。name 参数指定要导入的模块,以绝对或相对形式(例如,
pkg.mod
或..mod
)导入。如果以相对形式指定名称,则必须将 package 参数设置为将充当解析包名称的锚点的包的名称(例如,import_module('..mod', 'pkg.subpkg')
将导入pkg.mod
)。
例如
my_module = importlib.import_module('os.path')
解决方案 2:
对于 Python 2.7/3.1 之前的版本,基本上就是这样做的。
对于较新的版本,请参阅importlib.import_module
Python 2和Python 3。
或者__import__
您可以通过以下步骤导入模块列表:
>>> moduleNames = ['sys', 'os', 're', 'unittest']
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)
直接摘自《深入 Python》。
解决方案 3:
注意:自 Python 3.4 起, imp已被弃用,取而代之的是importlib
如上所述,imp模块为您提供了加载功能:
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
解决方案 4:
使用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)
# Verify contents of the module:
print(dir(module))
从这里开始,module
将是一个代表模块的模块对象(与通过执行pluginX
分配的相同)。因此,要调用中定义的函数(没有参数),请使用。pluginX
`import pluginXhello
pluginX`module.hello()
为了获得“导入”模块功能的效果from
,请将其存储在已加载模块的内存缓存中,然后执行相应的from
导入:
sys.modules[module_name] = module
from pluginX import hello
hello()
导入包
要导入包,只需调用即可。假设当前工作目录中import_module
有一个包文件夹;那么只需执行pluginX
import importlib
pkg = importlib.import_module('pluginX')
# check if it's all there..
print(dir(pkg))
解决方案 5:
使用imp 模块,或者更直接的__import__()
函数。
解决方案 6:
如果你想在本地使用它:
>>> 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()
解决方案 7:
您可以使用exec
:
exec("import myapp.commands.%s" % command)
解决方案 8:
与@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
解决方案 9:
下面的部分对我有用:
>>>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 脚本中导入:
python -c '<above entire code in one line>'
解决方案 10:
以下对我有用:
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
结果是动态加载的类“适配器”的列表。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件