学到了,学到了导入模块还能这么操作

简介: 学到了,学到了导入模块还能这么操作

导入模块的同时修改模块


问题核心:★★   口感:西湖牛肉羹

问题


你想给某个已存在模块中的函数添加装饰器。不过,前提是这个模块已经被导入并 且被使用过。


解决方案


这里问题的本质就是你想在模块被加载时执行某个动作。可能是你想在一个模块被加载时触发某个回调函数来通知你。


    import importlib
    import sys
    from collections import defaultdict
    _post_import_hooks = defaultdict(list)
    class PostImportFinder:
        def __init__(self):
            self._skip = set()
        def find_module(self, fullname, path=None):
            if fullname in self._skip:
         return None
        self._skip.add(fullname)
        return PostImportLoader(self)
    class PostImportLoader:
      def __init__(self, finder):
        self._finder = finder
      def load_module(self, fullname):
        importlib.import_module(fullname)
        module = sys.modules[fullname]
        for func in _post_import_hooks[fullname]:
          func(module)
          self._finder._skip.remove(fullname)
        return module
    def when_imported(fullname):
      def decorate(func):
        if fullname in sys.modules:
          func(sys.modules[fullname])
        else:
          _post_import_hooks[fullname].append(func)
        return func
      return decorate
    sys.meta_path.insert(0, PostImportFinder())

    这样,你就可以使用 when_imported() 装饰器了

    例如:

      >>> from postimport import when_imported
      >>> @when_imported('threading')
      ... def warn_threads(mod):
      ...   print('Threads? Are you crazy?')
      ...
      >>>
      >>> import threading
      Threads? Are you crazy?
      >>>

      作为一个更实际的例子,你可能想在已存在的定义上面添加装饰器如下所示:

        from functools import wraps
        from postimport import when_imported
        def logged(func):
          @wraps(func)
          def wrapper(*args, **kwargs):
            print('Calling', func.__name__, args, kwargs)
          return func(*args, **kwargs)
         return wrapper
        @when_imported('math')
        def add_logging(mod):
          mod.cos = logged(mod.cos)
          mod.sin = logged(mod.sin)
        



        结论


        @when_imported 装饰器的作用是注册在导入时被激活的处理器函数。该装饰器检查 sys.modules 来查看模块是否真的已经被加载了。如果是的话,该处理器被立即调用。不然, 处理器被添加到 _post_import_hooks 字典中的一个列表中去。

        _post_import_hooks 的作用就是收集所有的为每个模块注册的处理器对象。一个模块可以注册多个处理器。

        要让模块导入后触发添加的动作,PostImportFinder 类被设置为 sys.meta_path 第一个元素。它会捕获所有模块导入操作。

        本文中的 PostImportFinder 的作用并不是加载模块,而是自带导入完成 后触发相应的动作。实际的导入被委派给位于 sys.meta_path 中的其他查找器。

        PostImportLoader 类中的 imp.import_module() 函数被递归的调用。为了避免陷入无 线循环,PostImportFinder 保持了一个所有被加载过的模块集合。如果一个模块名存 在就会直接被忽略掉。

        当一个模块被 imp.import_module() 加载后,所有在 _post_import_hooks 被注 册的处理器被调用,使用新加载模块作为一个参数。有一点需要注意的是本机不适用于那些通过 imp.reload() 被显式加载的模块。也就是说,如果你加载一个之前已被加载过的模块,那么导入处理器将不会再被触发。另 外,要是你从 sys.modules 中删除模块然后再重新导入,处理器又会再一次触发。


        -END-


        ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌

        往期好文合集


        怎么还蹦出来个 “ 数据管道 ”<<戳这里

        Python 读取 JSON 数据的骚操作<<戳这里一切皆对象,那是我的对象<<戳这里


        最 后   


        若觉得文章不错,转发分享,也是我们继续更新的动力。在公众号内回复「资料」,即可免费获取 Python资料,期待你的关注~

        相关文章
        |
        3天前
        |
        存储 Java easyexcel
        导出导入开发场景
        导出导入开发场景
        |
        9月前
        |
        Linux Shell iOS开发
        【100天精通python】Day16:python模块_模块的搜索目录和导入模块异常时的处理方法
        【100天精通python】Day16:python模块_模块的搜索目录和导入模块异常时的处理方法
        93 0
        |
        10月前
        |
        Python
        导入名为'materials'的模块时出现了错误
        导入名为'materials'的模块时出现了错误
        78 2
        |
        12月前
        |
        数据挖掘 Python
        一日一技:在 Jupyter 中如何自动重新导入特定的 模块?
        一日一技:在 Jupyter 中如何自动重新导入特定的 模块?
        302 0
        5.ES6模块导出导入
        5.ES6模块导出导入
        52 0
        |
        开发者 Python
        导入模块 | 学习笔记
        快速学习导入模块
        131 0
        导入模块 | 学习笔记
        |
        开发者 Python
        导入模块的五种方法| 学习笔记
        快速学习导入模块的五种方法
        368 0
        |
        JSON 数据格式 Python
        Python基础 模块化编程(模块的导入) 模块化编程 模块以主程序的方式运行 包和目录 第三方库的安装和导入方法
        python基础知识模块,模块化编程,模块的创建和导入 python基础,模块的创建和导入,让模块以主程序的方式运行,python中的包和目录的区别和创建。模块导入另一个包的模块的方法,导入带有包的模块时的注意事项,常见的内置模块。 第三方模块的安装和导入的方法
        Python基础 模块化编程(模块的导入)   模块化编程 模块以主程序的方式运行 包和目录 第三方库的安装和导入方法
        |
        JavaScript
        ES6中模块导入遇到的问题及其解决办法
        今天遇到了一个小的问题,我们来看一下,情况是这样的:在没遇到过这个坑之前,如果需要引入一个模块,我通常的做法都是在HTML文件中内嵌一个script标签,并通过指定 type="module" 来实现;然而今天我却没有按照往常这样做,而是指定两个js文件,其中一个文件通过 export 暴露出需要的变量和函数,在另一个文件中通过 import 导入,结果就遇到了报错,来给各位看下报错信息:
        ES6中模块导入遇到的问题及其解决办法