3

我在 python 中有一些模块,它们是动态导入的,并且都具有相同的结构(plugin.py、models.py、tests.py、...)。在管理代码中,我想导入这些子模块,但例如 models.py 或 tests.py 不是强制性的。(所以我可以plugin_a.pluginplugin_a.tests只有plugin_b.plugin)。

我可以通过以下方式检查子模块是否存在

try:
    __import__(module_name + ".tests")
except ImportError:
    pass

如果module_name+".tests"未找到,那将失败,但如果tests-module 本身尝试导入某些未找到的内容,例如由于拼写错误,它也会失败。有什么方法可以检查模块是否存在,而不需要导入或确保ImportError仅由一个特定的导入操作引发?

4

4 回答 4

3

从traceback 的长度可以看出导入失败的深度有多少。缺少的.test模块只有一帧的回溯,直接依赖失败有两帧,等等。

Python 2 版本,sys.exc_info()用于访问回溯:

import sys


try:
    __import__(module_name + ".tests")
except ImportError:
    if sys.exc_info()[-1].tb_next is not None:
        print "Dependency import failed"
    else:
        print "No module {}.tests".format(module_name)

Python 3 版本,异常有一个__traceback__属性

try:
    __import__(module_name + ".tests")
except ImportError as exc:
    if exc.__traceback__.tb_next is not None:
        print("Dependency import failed")
    else:
        print("No module {}.tests".format(module_name))

演示:

>>> import sys
>>> def direct_import_failure(name):
...     try:
...         __import__(name)
...     except ImportError:
...         return sys.exc_info()[-1].tb_next is None
... 
>>> with open('foo.py', 'w') as foo:
...     foo.write("""\
... import bar
... """)
... 
>>> direct_import_failure('bar')
True
>>> direct_import_failure('foo')
False
于 2014-06-17T11:19:37.923 回答
2

继续:如何在不导入的情况下检查 python 模块是否存在

imp.find_module函数将返回一个 3 元素元组(文件、路径名、描述)或引发 ImportError。

如果模块有问题,它不会引发错误,只有当它不存在时。

python 文档建议您应该首先找到并导入包,然后在第二个中使用它的路径find_module,如有必要,递归执行此操作。

这对我来说似乎有点混乱。

下面的函数将检查给定模块的存在,在任何相对导入级别(module.py,,package.module.pypackage.subpackage.module.py)。

imp.find_module返回一个打开的文件,您可以在 中使用它imp.load_module,但这似乎也有点笨拙,所以我关闭了文件,以便可以在函数之外导入它。

请注意,这并不完美。如果您正在寻找package.subpackage.module但实际上package.subpackage是一个有效的模块,它也会返回 true。

import imp
import importlib

def module_exists(modulename):
    modlist = modulename.split('.')
    pathlist = None
    for mod in modlist:
        print mod
        try:
            openfile, pathname, desc = imp.find_module(mod,pathlist)
            pathlist = [pathname]
        except ImportError:
            print "Module '{}' does not exist".format(mod)
            return(False)
        else:
            print 'found {}'.format(openfile)
            if openfile:
                openfile.close()
                return(True)

if __name__ == '__main__':
    mymodule = 'parrot.type.norwegian_blue'
    if module_exists(mymodule):
        importlib.import_module(mymodule)

另请注意,我使用importlib.import_module的是__import__.

最后,请注意importlib是 Python 2.7 及更高版本

于 2014-06-17T08:16:11.550 回答
1

有没有办法检查模块是否存在,而不导入它或确保 ImportError 仅由一个特定的导入操作引发?

失败可能有多种原因,ImportError因为导入会评估模块;如果存在语法错误,模块将无法加载。

要检查模块是否存在而不加载它,请使用pkgutil.find_loader,如下所示:

>>> pkgutil.find_loader('requests')
<pkgutil.ImpLoader instance at 0x9a9ce8c>
>>> pkgutil.find_loader('foo')

它将返回一个ImpLoader实例,或者None如果包不可导入。您可以从ImpLoader实例中获取更多详细信息,例如模块的路径:

>>> pkgutil.find_loader('django').filename
'/usr/local/lib/python2.7/dist-packages/django'
于 2014-06-17T08:07:13.200 回答
1

如果模块不存在,您知道导入错误消息会是什么样子,因此只需检查一下:

try:
    module = module_name + '.tests'
    __import__(module)
except ImportError, e:
    if e.args and e.args[0] == 'No module named ' + module:
        print(module, 'does not exist')
    else:
        print(module, 'failed to import')
于 2013-05-18T16:35:16.643 回答