Python 如何导入名为字符串的模块?
我正在编写一个以命令作为参数的Python应用程序,例如:Python 如何导入名为字符串的模块?,python,python-import,Python,Python Import,我正在编写一个以命令作为参数的Python应用程序,例如: $ python myapp.py command1 我希望应用程序是可扩展的,也就是说,能够添加实现新命令的新模块,而无需更改主应用程序源。这棵树看起来像: myapp/ __init__.py commands/ __init__.py command1.py command2.py foo.py bar.py command = sys.argv[
$ python myapp.py command1
我希望应用程序是可扩展的,也就是说,能够添加实现新命令的新模块,而无需更改主应用程序源。这棵树看起来像:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
因此,我希望应用程序在运行时找到可用的命令模块,并执行相应的命令模块
Python定义了一个_导入_函数,该函数采用一个字符串作为模块名:
__导入名称,全局值=None,局部值=None,fromlist=,级别=0
该函数导入模块名,可能使用给定的全局变量和局部变量来确定如何在包上下文中解释该名称。fromlist提供了对象或子模块的名称,这些对象或子模块应根据名称从模块中导入
资料来源:
所以现在我有一些类似的东西:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
这工作得很好,我只是想知道是否有一种更惯用的方法来完成我们用这段代码所做的事情
请注意,我特别不想使用鸡蛋或扩展点。这不是一个开源项目,我不希望有插件。要点是简化主应用程序代码,并消除每次添加新命令模块时对其进行修改的需要。您可以使用:
对于早于2.7/3.1的Python,这就是您的工作方式 有关较新版本,请参阅和的importlib.import_模块 如果愿意,也可以使用exec 或者使用_u导入_u,您可以通过以下操作导入模块列表:
>>> moduleNames = ['sys', 'os', 're', 'unittest']
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)
直接从中删除。使用或更直接的功能
注意:imp不推荐使用,因为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]())
>>>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();
它从文件夹“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)]'
同样适用于globalsPython 2.7和3.1及更高版本的推荐方法是使用模块: importlib.import\u modulename,package=None 导入模块。name参数以绝对或相对术语指定要导入的模块,例如pkg.mod或..mod。如果名称是以相对术语指定的,则必须将package参数设置为包的名称,该名称将用作解析包名称的锚点,例如导入模块“…mod”,“pkg.subpkg”将导入pkg.mod e、 g
与@monkut的解决方案类似,但可重用且容错,如下所述:
下面的作品对我很有用:
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]())
>>>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>'
例如,我的模块名称类似于jan_模块/feb_模块/mar_模块 现在你应该使用 导入源文件 这本书实际上提供了一个配方,它是这样的:
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),位于其名称空间下;例如,module.hello
如果要导入成员(例如,hello),可以在内存中的模块列表中包含模块/pluginX:
sys.modules[module_name] = module
from pluginX import hello
hello()
导入包
在当前目录下导入一个包,例如pluginX/__init__u;.py实际上很简单:
import importlib
pkg = importlib.import_module('pluginX')
# check if it's all there..
def bla(mod):
print(dir(mod))
bla(pkg)
如何通过exec获取模块的句柄,以便在本例中调用.run方法?然后可以执行getattrmyapp.commands、command以访问模块。。。。或者将as command_module添加到import语句的末尾,然后执行command_module.runIn。在某些版本的Python 3+exec中,该函数被转换为一个函数,其附加优点是,在源代码中创建的引用结果被存储到exec的locals参数中。要进一步将引用的exec与本地代码块本地代码隔离,您可以提供自己的dict(如空dict),并使用该dict引用引用,或将该dict传递给其他函数execsource、gobals、command1_dict。。。。printcommand1_dict['somevarible']fromlist=[myapp.commands]做什么?@PieterMüller:在python shell类型中,这是:dir_uuuimport_uuu。fromlist应该是一个名称列表,以模拟FromName导入…从2019年起,您应该查找importlib:不要使用_导入_;请参阅使用好的简单解决方案。我想我们写了一个类似的:但是你的有一些缺陷:例外情况呢?错误和恐怖?为什么不先检查编译版本,然后再检查源版本呢。期望类会降低y中的可重用性
我们的例子。在目标模块中构造MyClass的行中,您正在向类名添加一个冗余引用。它已存储在预期的\u类中,因此您可以执行class\u inst=getattrpy\u mod,而不是预期的\u name。请注意,如果存在后缀为.pyc或.pyo的正确匹配字节编译文件,则将使用它而不是解析给定的源文件。提醒:这个解决方案有效;但是,imp模块将被弃用以支持导入库,请参见imp的页面:从版本3.4开始弃用:imp包将被弃用以支持导入库。请不要在注释中不提供原因就隐藏答案。它对任何人都没有帮助。我想知道为什么这是不好的东西。和我一样,因为我不熟悉Python,我想知道为什么这是不好的。这不只是因为它是不好的Python,而且它通常是不好的代码。什么是fl?for循环定义过于复杂。路径是硬编码的,例如,不相关。它使用的是不受欢迎的python导入,所有这些fl[i]东西是干什么用的?这基本上是不可读的,对于一些不太难理解的东西来说,这是不必要的复杂-请看投票结果最靠前的答案及其一行代码。执行的区别是什么?OP的这种解决方案的一个问题是,为一个或两个错误的命令模块捕获异常会使他/她的整个命令应用程序在一个异常上失败。就我个人而言,我希望通过try:mods=\uuuuu import\uuuuu\nexcept ImportError as error:reporterror单独包装每个导入,以允许其他命令继续工作,而坏命令得到修复。正如Denis Malinovsky在下面指出的那样,此解决方案的另一个问题是python文档本身建议不要使用uuuuu import\uuuu。2.7文档:由于此函数是供Python解释器使用的,而不是一般用途,因此最好使用importlib.import_模块。。。当使用python3时,imp模块解决了这个问题,正如monkut在下面提到的那样。@JohnWu为什么在有for元素in和map的情况下需要foreach:注意,map在python3中不起作用,由于map现在使用惰性评估。建议由哪个来源或机构推荐?文档建议使用_导入_函数来支持上述模块。这对于导入os.path非常有效;如何从os.path导入*?我在这里得到答案,即调用globals.updatemy_模块__dict@NamGVU,这是一种危险的方法,因为它会污染全局,并且会覆盖任何具有相同名称的标识符。您发布的链接具有此代码的更好、改进的版本。add sys.modules[module_name]=如果您希望能够导入模块\u名称,请将模块添加到代码末尾afterwards@DanielBraun执行此操作时,get me error>ModuleNotFoundError不使用_导入__;请参阅为内置局部变量使用函数明确警告不应修改此词典的内容。