问题来源:
为了支持模型的切换功能,拟通过调用不同模型路径下的predict.py方法来实现。这就涉及到调用外部py文件。调用外部py文件,有多种方式:
方法一:sys.path
1 import sys
2 sys.path.insert(0, modelPath) # 设置该目录拥有最高优先级
3 import predict
问题1:不符合python的PEP-8规范(即import语句应放在代码的最前面),可参考这篇给出的解决方案:
问题2:使用sys.path时,在程序运行过程中始终有效,每次使用后应注意及时删除已添加的路径。
1 # 定义
2 class add_path:
3 def __init__(self, path):
4 self.path = path
5
6 def __enter__(self):
7 sys.path.insert(0, self.path)
8
9 def __exit__(self, exc_type, exc_value, traceback):
10 try:
11 sys.path.remove(self.path)
12 except ValueError:
13 pass
1 # 使用
2 with add_path(modelPath):
3 import predict
4 XXXX
问题2-1:但进一步在真实的使用中发现,尽管我们在sys.path中删除了对应的路径,下次import predict时仍然会延续上一次的引入结果。这是因为sys.modules缓存路径(python在import module前,先会去sys.modules看看曾经有没有导入过这个模块)如果已经导入过就不会再从sys.path中重复读取,所以尽管我们已经改变了sys.path的内容,import predict仍然维持第一次的引入内容。
方案1:(已解决)解决方法是尝试删除sys.modules中的缓存内容
1 class add_path:
2 def __init__(self, path):
3 self.path = path
4
5 def __enter__(self):
6 sys.path.insert(0, self.path)
7
8 def __exit__(self, exc_type, exc_value, traceback):
9 try:
10 sys.path.remove(self.path)
11 # modules中的缓存名称与import的名称一致,可直接删除对应的缓存
12 # (但前提是该import仅在这一处使用)
13 if "predict" in sys.modules:
14 del sys.modules['predict']
15 except ValueError:
16 pass
方案2:(未实现)引入多进程,每次调用完成后杀死进程,进程推出时会自动清空缓存。
另外一个思路是,考虑到对于sys.path的修改会在程序执行结束时失效,可以考虑开一个独立的进程引入模型包实现抽取功能,抽取结束后杀死进程。
方法二:使用 python 标准库 importlib 加载特定路径
参考stackoverflow链接,试了下发现这种方法只能导入一个python文件。遗留问题:如何导入一个目录
1 # 导入指定python文件
2 def load_package_from_path(pkg_path: str) -> ModuleType:
3 """
4 ref: https://stackoverflow.com/a/50395128
5 """
6 name = basename(pkg_path)
7
8 spec = util.spec_from_file_location(name, pkg_path)
9 module = util.module_from_spec(spec)
10 sys.modules[spec.name] = module
11 spec.loader.exec_module(module)
12
13 return module
参考: