• 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
  • 相关阅读:
    1 win10双系统安装ubuntu16.04和18.04(问题详细记录)
    一些操作记录备查
    SecureCRT中文乱码解决方法
    Oracle中的NVL函数
    本机不安装Oracle客户端,使用PL/SQL Developer连接远程数据库
    DevExpress DateEdit控件选择精确到秒
    DevExpress GridView 整理
    Linux 删除文件夹和文件的命令
    DevExpress之XtraReport 学习
    解决Visual Studio Community 2017工具栏中没有Report Viewer的问题
  • 原文地址:https://www.cnblogs.com/Mufasa/p/10482923.html
Copyright © 2020-2023  润新知