问题:如何导入给定名称的模块为字符串?
我正在编写一个以命令作为参数的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)
该函数导入模块名称,可能使用给定的全局变量和局部变量来确定如何在程序包上下文中解释该名称。fromlist提供应从名称给定的模块中导入的对象或子模块的名称。
来源: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()
这工作得很好,我只是想知道是否可能有一种更惯用的方式来完成我们对这段代码所做的工作。
请注意,我特别不想使用鸡蛋或延伸点。这不是一个开源项目,我不希望有“插件”。关键是简化主应用程序代码,并且每次添加新命令模块时都无需对其进行修改。
回答 0
使用2.7 / 3.1之前的Python,这就是您要做的事情。
对于较新的版本,看到importlib.import_module
了Python的2和和Python 3中。
您也可以使用exec
。
或者,__import__
您可以通过执行以下操作导入模块列表:
>>> moduleNames = ['sys', 'os', 're', 'unittest']
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)
直接从Dive Into Python翻录。
回答 1
对于Python 2.7和3.1及更高版本,推荐的方法是使用importlib
模块:
importlib.import_module(名称,包=无)
导入模块。name参数以绝对或相对方式指定要导入的模块(例如pkg.mod或..mod)。如果使用相对术语指定名称,则必须将package参数设置为充当解析包名称的定位符的包的名称(例如import_module(’.. mod’,’pkg.subpkg’)将导入pkg.mod)。
例如
my_module = importlib.import_module('os.path')
回答 2
注意:自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
回答 3
使用imp模块或更直接的__import__()
功能。
回答 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)
# check if it's all there..
def bla(mod):
print(dir(mod))
bla(module)
导入包裹
实际上,在当前目录下导入包(例如pluginX/__init__.py
)非常简单:
import importlib
pkg = importlib.import_module('pluginX')
# check if it's all there..
def bla(mod):
print(dir(mod))
bla(pkg)
回答 5
如果您想在本地人中使用它:
>>> 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()
回答 6
您可以使用exec
:
exec("import myapp.commands.%s" % command)
回答 7
与@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
回答 8
以下内容对我有用:
>>>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>'
回答 9
例如,我的模块名称类似于jan_module
/ feb_module
/ mar_module
。
month = 'feb'
exec 'from %s_module import *'%(month)
回答 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
结果是动态加载的类“适配器”的列表。