1. 程式人生 > >lazy_import源碼解析(原創)

lazy_import源碼解析(原創)

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的功能函數
 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 = fmodule {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源碼解析(原創)