17.2.6.4 定制导入工具
通过修改搜索路径,程序员可以控制如何找到标准Python模块。不过,如果一个程序需要导入其他地方的代码,而不是从文件系统上常规的.py或.pyc文件导入,那么又该怎么做呢?PEP 302解决了这个问题,通过引入导入hook的思想,它会捕获到在搜索路径上查找一个模块的意图,并采用候选策略从其他位置加载代码或者对它做预处理。
可以通过两个不同阶段来实现定制导入工具。查找工具(finder)负责找到一个模块,并提供一个加载工具(loader)来管理具体的导入。可以向sys.path_hooks列表追加一个工厂来增加定制模块查找工具。导入时,会把路径的各个部分提供给一个查找工具,直到一个部分声称提供支持(不产生ImportError)。然后,查找工具负责搜索数据存储(由对应命名模块的路径入口表示)。
import sys
class NoisyImportFinder:
PATH_TRIGGER = 'NoisyImportFinder_PATH_TRIGGER'
def __init__(self,path_entry):
print('Checking {}:'.format(path_entry),end=' ')
if path_entry != self.PATH_TRIGGER:
print('wrong finder')
raise ImportError()
else:
print('works')
return
def find_module(self,fullname,path=None):
print('Looking for {!r}'.format(fullname))
sys.path_hooks.append(NoisyImportFinder)
for hook in sys.path_hooks:
print('Path hook: {}'.format(hook))
sys.path.insert(0,NoisyImportFinder.PATH_TRIGGER)
try:
print('importing target_module')
import target_module
except Exception as e:
print('Import failed:',e)
这个例子展示了如何实例化和查询查找工具。如果提供的路径入口与查找工具的特殊触发值不匹配,这显然不是文件系统上的一个真正的路径,那么实例化时NoisyImportFinder会产生一个ImportError。这个测试可以避免NoisyImportFinder破坏真正模块的导入。