Python 3导入挂钩

时间:2016-09-09 19:52:34

标签: python python-3.x

我正在尝试实施"导入挂钩"在Python 3.钩子应该为每个导入的类添加一个属性。 (并非真正每个类,但为了简化问题,我们假设这样。)

我有一个加载器定义如下:

import sys

class ConfigurableImports(object):

    def find_module(self, fullname, path):
        return self

    def create_module(self, spec):
        # ???

    def exec_module(self, module):
        # ???

sys.meta_path = [ConfigurableImports()]

文档指出,从3.6开始,加载器必须同时实现create_moduleexec_module。但是,文档也没有说明应该如何实现这些,而且没有示例。我的用例非常简单,因为我只加载Python模块,并且加载器的行为应该与默认行为几乎完全相同。

如果可以的话,我只需使用importlib.import_module,然后相应地修改模块内容;但是,由于importlib利用了import钩子,我得到了无限递归。

编辑:我还尝试使用imp模块load_module,但不推荐使用此功能。

使用导入钩子有没有简单的方法来实现这个功能,或者我是否采用了错误的方式?

1 个答案:

答案 0 :(得分:1)

Imho,如果您只需要更改模块,即在找到并加载模块之后使用它,则无需实际创建查找,加载和返回模块的完整挂钩;只需修补__import__

这可以通过几行轻松完成:

import builtins 
from inspect import getmembers, isclass

old_imp = builtins.__import__

def add_attr(mod):
    for name, val in getmembers(mod):
        if isclass(val):
            setattr(val, 'a', 10)

def custom_import(*args, **kwargs):
    m = old_imp(*args, **kwargs)
    add_attr(m)
    return m

builtins.__import__ = custom_import

在这里,__import__被您的自定义导入替换,该导入调用原始__import__来获取已加载的模块,然后调用一个函数add_attr来执行对类中的类的实际修改返回模块之前的模块(来自getmembers的{​​{1}}和isclass)。

当然,这是以一种方式创建的,当您inspect脚本时,会进行更改。

您可以并且可能应该创建import的辅助功能,并在需要时再次更改它,例如:

restore

上下文管理器也可能是一个很酷的补充。

所以你可以在需要获取

时调用它