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应用程序,例如:

$ 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定义了一个\uuuuuuuuuuuuuuuuuuu函数,该函数使用一个字符串作为模块名:

__导入(名称,全局=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,这就是您的工作方式

有关较新版本,请参阅和的导入lib.import_模块

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

或者使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

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

同样适用于
globals()

Python 2.7和3.1及更高版本的推荐方法是使用模块:

importlib.import_模块(名称,包=None)

导入模块。name参数指定要以绝对或相对方式导入的模块(例如pkg.mod或..mod)。如果名称是以相对术语指定的,则必须将package参数设置为作为解析包名称的锚点的包的名称(例如,import_module(“…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>'
python-c''

例如,我的模块名称类似于
jan\u模块
/
feb\u模块
/
mar\u模块

month = 'feb'
exec 'from %s_module import *'%(month)
现在你应该使用

导入源文件 这本书实际上提供了一个配方,它是这样的:

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
——在该代码段的名称空间下调用
module
——访问成员(例如,函数“
hello
”);例如,
module.hello()

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

sys.modules[module_name] = module

from pluginX import hello
hello()
导入包 在当前目录下导入一个包(例如,
pluginX/\uuuu init\uuuuu.py
)实际上很简单:

import importlib

pkg = importlib.import_module('pluginX')

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

如何通过exec获得模块的句柄,以便调用(在本例中).run()方法?然后可以执行getattr(myapp.commands,command)来访问模块。。。。或者将
as command\u module
添加到import语句的末尾,然后执行
command\u module.run()
在某些版本的Python 3+exec中被转换成一个函数,其附加的好处是,在源代码中创建的引用结果被存储到exec()的locals()参数中。为了进一步将引用的exec与本地代码块局部代码隔离开来,您可以提供自己的dict(如空dict),并使用该dict引用引用引用,或者将该dict传递给其他函数exec(source,gobals(),command1_dict)。。。。print(command1_dict['somevarible'])fromlist=[“myapp.commands”]做什么?@PieterMüller:在python shell中键入以下内容:
dir(\uu导入)
。fromlist应该是模拟“from name import…”的名称列表。从2019年起,您应该查找
importlib
:不要使用“导入”\uuuuuuuuuuuuuuuu请参阅使用好的简单解决方案。我想我们写了一个类似的:但是你的有一些缺陷:例外情况呢?错误和恐怖?为什么不先检查编译版本,然后再检查源版本呢。在您的情况下,需要一个类会降低可重用性。在目标模块中构造MyClass的行中,您添加了对类名的冗余引用。它已经存储在
expected\u class
中,因此您可以改为执行
class\u inst=getattr(py\u mod,expected\u name)(
)。请注意,如果存在正确匹配的字节编译文件(后缀为.pyc或.pyo),则将使用它而不是解析给定的源文件。提醒:这个解决方案有效;但是,imp模块将被弃用以支持导入库,请参见imp的页面:“从版本3.4开始弃用”:imp包将被弃用以支持导入库。