我正在编写一个以命令为参数的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()
这工作得很好,我只是想知道是否可能有一种更惯用的方式来完成我们对这段代码所做的工作。
请注意,我特别不想使用鸡蛋或延伸点。 这不是一个开源项目,我不希望有“插件”。 关键是简化主应用程序代码,并且每次添加新的命令模块时都无需对其进行修改。
#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楼
与@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
#3楼
您可以使用exec
:
exec "import myapp.commands.%s" % command
#4楼
对于2.7 / 3.1之前的Python,这几乎就是您的操作方式。
有关较新的版本,请参阅importlib.import_module
于Python 2和Python 3的 importlib.import_module
。
您也可以使用exec
。
或者使用__import__
您可以通过执行以下操作导入模块列表:
>>> moduleNames = ['sys', 'os', 're', 'unittest']
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)
直接从Dive Into Python翻录。
#5楼
使用imp模块或更直接的__import__()
函数。
#6楼
注意:自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
#7楼
以下为我工作:
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
结果是动态加载的类“适配器”的列表。
#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楼
现在,您应该使用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)
#11楼
如果您想在本地人中使用它:
>>> 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()