zoukankan      html  css  js  c++  java
  • lazy_import源码解析(原创)

    参考链接:

    An approach to lazy importing in Python 3.7(这个是参考源)

    Python3.7中一种懒加载的方式(中文翻译)

    原博客核心:

    以前的两种惰性/延迟加载方法:

      ①本地子功能区加载而非程序启动时的全局加载。直到你的程序运行需要这个库的时候才进行加载;缺点:易重复载入库文件、容易遗忘库载入的范围。

      ②惰性加载。需要模块的时候触发 ModuleNotFoundError  提前发现这个模块,而延迟的只是后续补加载过程;缺点:显式优于隐式、如果一个模块希望立即加载,那么在延迟加载时,它可能会严重崩溃。(Mercurial实际上开发了一个模块黑名单,以避免延迟加载来解决这个问题,但是他们必须确保对其进行更新,因此这也不是一个完美的解决方案。)

     

    博主提出来的最新的方法:

      在Python 3.7中,模块现在可以在其上定义__getattr__(),允许编写一个函数,在模块上的属性不可用时导入模块。这样做的缺点是使它成为一个惰性导入而不是一个加载,因此很晚才发现是否会引发ModuleNotFoundError。但是它是显式的,并且仍然是为您的模块全局定义的,因此更容易控制。

    改进方向:发现导入错误被推迟,如何提前获知这个可能出现的导入错误防止程序抛出异常并终止。

    代码段1:demo1.py

     1 import importlib
     2 
     3 # 这个是实现lazy_import的功能函数
     4 def lazy_import(importer_name, to_import):
     5     module = importlib.import_module(importer_name) # 直接加载调用的后一级函数
     6 
     7     import_mapping = {} # 字典 键名:有可能为缩写名  值名:为原始可查找库名,例如:import_mapping['np'] = 'numpy'
     8     for name in to_import:
     9         importing, _, binding = name.partition(' as ')
    10         if not binding:
    11             _, _, binding = importing.rpartition('.')
    12         import_mapping[binding] = importing
    13 
    14     def __getattr__(name):
    15         if name not in import_mapping:  # 如果这个库没在import_mapping中,就抛出异常错误,并且中断
    16             message = f'module {importer_name!r} has no attribute {name!r}'
    17             raise AttributeError(message)
    18         importing = import_mapping[name]
    19         imported = importlib.import_module(importing,module.__spec__.parent)
    20         # print('name=',name,'module=',module,'module.__spec__=',module.__spec__,'module.__spec__.parent=',module.__spec__.parent)
    21         setattr(module, name, imported) # sub, np, numpy
    22         return imported
    23 
    24     return module, __getattr__  #返回一个库和一个方法

    代码段2:sub.py

    lazy_import 在python3.7中已经可以直接使用了
     1 # In pkg/__init__.py with a pkg/sub.py.
     2 import demo1
     3 
     4 # print('sub.py中的__name__ =', __name__)  #当其他程序调用这个程序的时候 __name__ = 'sub',自己为主程序的时候为 '__main__',这里我第一次使用的时候就出错了,直接在这个程序中测试
     5 mod, __getattr__ = demo1.lazy_import(__name__, {'sys', '.sub as thingy', 'numpy as np'})
     6 
     7 
     8 def test1():
     9     print('sys运行正常')
    10     return mod.sys
    11 
    12 
    13 def test2():
    14     return mod.thingy.answer
    15 
    16 
    17 def test3():
    18     print('numpy运行正常')
    19     return mod.np

    代码段3:mid_test.py

     1 import sub
     2 
     3 ### 异常检测,str_out是不存在的,抛出异常处理
     4 # module1 = sub.str_out()
     5 
     6 module2 = sub.test3()
     7 print(module2)
     8 # <module 'numpy' from 'C:\ProgramData\Anaconda3\envs\lib\site-packages\numpy\__init__.py'>
     9 
    10 print(module2.array([1, 2, 3, 4]))
    11 # [1 2 3 4]
    12 
    13 print(module2.__spec__)
    14 # ModuleSpec(
    15 # name='numpy',
    16 # loader=<_frozen_importlib_external.SourceFileLoader object at 0x000001E4879A6F98>,
    17 # origin='C:\ProgramData\Anaconda3\envs\lib\site-packages\numpy\__init__.py',
    18 # submodule_search_locations=['C:\ProgramData\Anaconda3\envs\lib\site-packages\numpy'])
    19 
    20 print(module2.__spec__.parent)
    21 # numpy
  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/Mufasa/p/10482923.html
Copyright © 2011-2022 走看看