覆盖`import`以获得更复杂的模块导入

时间:2017-07-11 12:11:16

标签: python import

是否有可能以某种方式覆盖import,以便我可以在导入之前对模块执行更复杂的操作?

作为示例:我有一个更大的应用程序,它使用matplotlib作为对应用程序的整体功能不重要的辅助功​​能。如果未安装matplotlib,我只想模拟功能,以便导入和对matplotlib函数的所有调用似乎都有效,只是没有实际做任何事情。然后,一个简单的警告应该表明模块没有安装,尽管这个事实不会损害应用程序的核心功能。我已经有一个导入函数,在没有安装matplotlib的情况下,返回一个MagicMock对象而不是实际模块,它只是模仿matplotlib API的行为。

因此,所有import matplotlib...from matplotlib import...应该被相应的函数调用自动覆盖。我可以手动替换所有importfrom ... import表达式,但我想制作,但有很多。我希望通过覆盖import来自动拥有此功能。

这可能吗?

2 个答案:

答案 0 :(得分:2)

我发现的最简单方法是将__import__函数替换为您自己的实现(描述为here)。然后,如果有人试图导入matplotlib,您只需导入另一个模块:

def _import(name, *args, **kwargs):
    if name == 'matplotlib': # if someone tries to import matplotlib...
        name = 'my_mocked_matplotlib' # ...import the mocked version instead
    return original_import(name, *args, **kwargs)

import builtins
original_import = builtins.__import__
builtins.__import__ = _import

要将自定义导入行为限制为仅限几个模块,您可以使用内省(使用inspect module)找出导入执行的模块:

import inspect

def _import(name, *args, **kwargs):
    if name == 'matplotlib': # if someone tries to import matplotlib...
        # find out which module is performing the import
        frame = inspect.currentframe().f_back
        module_path = frame.f_globals['__file__']

        # if the import is happening in module1 or module2, redirect it
        if module_path in ('/path/to/module1.py','/path/to/module2.py'):
            name = 'my_mocked_matplotlib' # ...import the mocked version instead

    return original_import(name, *args, **kwargs)

答案 1 :(得分:0)

简短回答是 ......但是当模块不存在时,你可以而且应该抓住ImportError,然后处理它。否则用其他东西替换所有import语句是很聪明的事情。