赞
踩
最近看了看importlib库的的源码,先插个眼,后续有新理解再继续更新
模块的加载:
先找到模块描述 spec_from_file_location
再将描述初始化成一个module类 module_from_spec
最后放入python的exec()中 spec(模块声明).loader.exec_module(module(根据模块声明生成的模块类))
即完成了对某个模块的加载
#__all__ = ['__import__', 'import_module', 'invalidate_caches', 'reload'] # 先插个眼,后续加深对该部分代码的理解 # =================================__import__方法================================== # 方法实现代码如下,返回字符串形式的模块名 """ def __import__(name, globals=None, locals=None, fromlist=(), level=0): if level == 0: # 阅读源码发现该方法根据传入的模块名,会使用sys.module的方法去解释器中查询该模块是否存在 module = _gcd_import(name) else: globals_ = globals if globals is not None else {} package = _calc___package__(globals_) module = _gcd_import(name, package, level) if not fromlist: if level == 0: return _gcd_import(name.partition('.')[0]) elif not name: return module else: cut_off = len(name) - len(name.partition('.')[0]) return sys.modules[module.__name__[:len(module.__name__)-cut_off]] elif hasattr(module, '__path__'): return _handle_fromlist(module, fromlist, _gcd_import) else: return module """ # =====================================import_module方法=================================== # 与__import__方法类似,都是通过sys.module方法查询解释器中有无该方法 """ def import_module(name, package=None): level = 0 if name.startswith('.'): if not package: msg = ("the 'package' argument is required to perform a relative " "import for {!r}") raise TypeError(msg.format(name)) for character in name: if character != '.': break level += 1 return _bootstrap._gcd_import(name[level:], package, level) """ # ========================================invalidate_caches方法========================================== # 用于清除查找器缓存 import importlib """ def invalidate_caches(): for finder in sys.meta_path: if hasattr(finder, 'invalidate_caches'): finder.invalidate_caches() """ # ==========================================reload方法============================== # 将方法塞入sys.module中并执行 # =======================_gcd_import方法============================= """ def _gcd_import(name, package=None, level=0): _sanity_check(name, package, level) # 检查包命名规范 if level > 0: name = _resolve_name(name, package, level) return _find_and_load(name, _gcd_import) """ # 判断模块式否在解释器中运行如果不在 """ def _find_and_load(name, import_): with _ModuleLockManager(name): module = sys.modules.get(name, _NEEDS_LOADING) if module is _NEEDS_LOADING: return _find_and_load_unlocked(name, import_) if module is None: message = ('import of {} halted; ' 'None in sys.modules'.format(name)) raise ModuleNotFoundError(message, name=name) _lock_unlock_module(name) return module """ # 此方法主要涉及两个方法,可实现跨域调模块 # spec_from_file_location(module,"path")/ module_from_spec(spec) / spec.loader.exec_module(module) # 本人另一篇博客有相应方法的应用 https://blog.csdn.net/weixin_44534915/article/details/123003919 """ def _find_and_load_unlocked(name, import_): path = None parent = name.rpartition('.')[0] if parent: if parent not in sys.modules: _call_with_frames_removed(import_, parent) # Crazy side-effects! if name in sys.modules: return sys.modules[name] parent_module = sys.modules[parent] try: path = parent_module.__path__ except AttributeError: msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent) raise ModuleNotFoundError(msg, name=name) from None spec = _find_spec(name, path) # 该方法会根据路径找到存在的模块并返回模块说明,具体方法主要是spec_from_file_location方法 if spec is None: raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) else: module = _load_unlocked(spec) # 加载模块声明,module_from_spec主要是这个方法,并用spec.loader.exec_module(module)写入解释器 if parent: # Set the module as an attribute on its parent. parent_module = sys.modules[parent] child = name.rpartition('.')[2] try: setattr(parent_module, child, module) except AttributeError: msg = f"Cannot set an attribute on {parent!r} for child module {child!r}" _warnings.warn(msg, ImportWarning) return module """ # ==================================关于spec_from_file_location模块声明方法 =================================== """ def spec_from_file_location(name, location=None, *, loader=None, submodule_search_locations=_POPULATE): if location is None: location = '<unknown>' if hasattr(loader, 'get_filename'): try: location = loader.get_filename(name) except ImportError: pass else: location = _os.fspath(location) # 根据传入的路径寻找模块找到对应文件 spec = _bootstrap.ModuleSpec(name, loader, origin=location) spec._set_fileattr = True if loader is None: for loader_class, suffixes in _get_supported_file_loaders(): if location.endswith(tuple(suffixes)): loader = loader_class(name, location) spec.loader = loader break else: return None if submodule_search_locations is _POPULATE: if hasattr(loader, 'is_package'): try: is_package = loader.is_package(name) except ImportError: pass else: if is_package: spec.submodule_search_locations = [] else: spec.submodule_search_locations = submodule_search_locations if spec.submodule_search_locations == []: if location: dirname = _path_split(location)[0] spec.submodule_search_locations.append(dirname) return spec """ # ============================module_from_spec根据模块描述生成模块类 ============================================== """ def module_from_spec(spec): # Typically loaders will not implement create_module(). module = None if hasattr(spec.loader, 'create_module'): # If create_module() returns `None` then it means default # module creation should be used. module = spec.loader.create_module(spec) elif hasattr(spec.loader, 'exec_module'): raise ImportError('loaders that define exec_module() ' 'must also define create_module()') if module is None: module = _new_module(spec.name) _init_module_attrs(spec, module) # 初始化一个module类 return module """ # =========================================spec(模块声明).loader.exec_module(module(根据模块声明生成的模块类)) """ module_desc.loader.exec_module(moudle_spec) #最终是执行的pthon内置方法exec() """
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。