lazy_import源碼解析(原創)
阿新 • • 發佈:2019-03-06
esp 一個 span tails spec rtl pin 不存在 觸發
參考鏈接:
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的功能函數 4def 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
lazy_import源碼解析(原創)