覆盖`import`以进行更复杂的模块导入

Hen*_*ese 7 python import

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

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

因此, all import matplotlib...orfrom matplotlib import...应该被相应的函数调用自动覆盖。我可以手动替换所有importfrom ... import表达式,但我想制作但有很多。我宁愿通过覆盖import.

那可能吗?

Ara*_*Fey 6

我发现的最简单的方法是__import__用您自己的实现(在此处描述)替换该函数。然后,如果有人尝试 import 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
Run Code Online (Sandbox Code Playgroud)

要将自定义导入行为限制为仅几个模块,您可以使用自省(使用检查模块)来找出从哪个模块执行了导入:

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)
Run Code Online (Sandbox Code Playgroud)