協議涉及兩個對象: Finder 和 loaderhtml
實現了方法:
finder.find_module(fullname, path=None)
python
返回一個loader對象或者None。git
實現了方法: loader.load_module(fullname)
github
返回一個module對象或者raise an exceptionapp
參考:pep302ide
hooks有兩種,一種是Meta hooks,一種是Path hooks。 註冊方式:spa
import importlib.machinery import sys # For illustrative purposes only. SpamMetaPathFinder = importlib.machinery.PathFinder SpamPathEntryFinder = importlib.machinery.FileFinder loader_details = (importlib.machinery.SourceFileLoader, importlib.machinery.SOURCE_SUFFIXES) # Setting up a meta path finder. # Make sure to put the finder in the proper location in the list in terms of # priority. sys.meta_path.append(SpamMetaPathFinder) # Setting up a path entry finder. # Make sure to put the path hook in the proper location in the list in terms # of priority. sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))
import importlib.util import sys def import_module(name, package=None): """An approximate implementation of import.""" absolute_name = importlib.util.resolve_name(name, package) try: return sys.modules[absolute_name] # 先查詢sys.modules except KeyError: pass path = None if '.' in absolute_name: parent_name, _, child_name = absolute_name.rpartition('.') parent_module = import_module(parent_name) path = parent_module.__spec__.submodule_search_locations for finder in sys.meta_path: # 再從sys.meta_path中獲取finder spec = finder.find_spec(absolute_name, path) if spec is not None: break else: msg = f'No module named {absolute_name!r}' raise ModuleNotFoundError(msg, name=absolute_name) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) sys.modules[absolute_name] = module if path is not None: setattr(parent_module, child_name, module) return module
其中: sys.meta_path[-1]
類型是<class '_frozen_importlib_external.PathFinder'>
, 這個對象調用了sys.path以及sys.path_hooks。htm
注意: 原本按照pep302的導入邏輯,是:對象
for mp in sys.meta_path: loader = mp(fullname) if loader is not None: <module> = loader.load_module(fullname) for path in sys.path: for hook in sys.path_hooks: try: importer = hook(path) except ImportError: # ImportError, so try the other path hooks pass else: loader = importer.find_module(fullname) <module> = loader.load_module(fullname) # Not found! raise ImportError
但後來(python3.4)引入了pep451, 接口名和調用方式發生了一些變化,使得流程如3所示。
主要參考:
pep302
pep451
importlib
New Import Hooks
Python 類庫引入機制