关于importlib 动态加载的使用
项目中有关于对Python包动态加载的需求,而且要求是不局限于当前目录下的全局导包,而且要能支持包更新,源程序同步更新
这里使用到了importlib这个包,先放出工具类
import importlib
import sys
import os
class NameConflictError(Exception):
def __init__(self, error_msg: str) -> None:
super().__init__(self)
self.error_msg = error_msg
def __str__(self) -> str:
return self.error_msg
class ModuleLoader(object):
@staticmethod
def get_module(module_name: str, package_path=None):
if package_path is None:
package_path = os.getcwd()
# Ensure wanted module import from wanted pkg
if package_path in sys.path:
sys.path.remove(package_path)
sys.path.insert(0, package_path)
mod = importlib.import_module(module_name)
exist_module_pkg_path = os.path.dirname(mod.__file__)
if package_path != exist_module_pkg_path:
mod = importlib.reload(mod)
# Read again
exist_module_pkg_path = os.path.dirname(mod.__file__)
if package_path != exist_module_pkg_path:
raise NameConflictError(
f"The module {package_path} not exist or priority lower than {exist_module_pkg_path}")
else:
return mod
@staticmethod
def get_member(module_name: str, func_name: str, package_path=None):
return getattr(ModuleLoader.get_module(module_name, package_path), func_name)
其实这边有几种导出场景是需要注意的,场景如下
前提A包为当前读取包,B包为历史已读入过的包 F为所需读取的函数(✅为相同 ❌为不同)
Pkg路径 | Module路径 | 函数名 | 结果 |
---|---|---|---|
❌ | ❌ | ❌ | A包有则成功,否则报错 |
❌ | ❌ | ✅ | A包有则成功,否则报错 |
❌ | ✅ | ❌ | 假如A包有F函数则读A包的F函数,否则读B包的F函数,均无则报错 |
✅ | ❌ | ❌or ✅ | A包有则成功,否则报错 |
其实总结下来,python内部维护了一个关于module独立的对象,当读入多个不同的同名module时,python只会更新修改过的函数或者添加新的函数,而不会对被删除的函数进行去除。
例如:
# test.A
def add():
return 100
def del():
return 500
# --------上下不同包--------
# try.A
def add():
return 200