如何通过字符串名称导入模块?

2024-06-13 08:04:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个Python应用程序,它将命令作为参数,例如:

$ python myapp.py command1

我希望应用程序是可扩展的,也就是说,能够添加实现新命令的新模块,而不必更改主应用程序源。这棵树看起来像:

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

所以我希望应用程序在运行时找到可用的命令模块并执行适当的命令模块。

Python定义了一个\u import\uu函数,该函数接受一个字符串作为模块名:

__import__(name, globals=None, locals=None, fromlist=(), level=0)

The function imports the module name, potentially using the given globals and locals to determine how to interpret the name in a package context. The fromlist gives the names of objects or submodules that should be imported from the module given by name.

Source: 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()

这工作得很好,我只是想知道是否有一种更习惯的方法来完成我们使用这段代码所做的工作。

请注意,我特别不想使用鸡蛋或扩展点。这不是一个开源项目,我不希望有“插件”。重点是简化主应用程序代码,并消除每次添加新命令模块时修改它的需要。


Tags: 模块the函数namepyimport命令应用程序
3条回答

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

importlib.import_module(name, package=None)

Import a module. The name argument specifies what module to import in absolute or relative terms (e.g. either pkg.mod or ..mod). If the name is specified in relative terms, then the package argument must be set to the name of the package which is to act as the anchor for resolving the package name (e.g. import_module('..mod', 'pkg.subpkg') will import pkg.mod).

例如

my_module = importlib.import_module('os.path')

对于2.7/3.1版本以上的Python,这基本上就是这样做的。

有关较新版本,请参见Python 2Python 3importlib.import_module

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

或者使用__import__可以通过执行以下操作导入模块列表:

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

直接从Dive Into Python上撕下。

Note: imp is deprecated since Python 3.4 in favor of 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

相关问题 更多 >