按照此处的 cPython 测试示例,我提出了以下潜在解决方案。当我意识到它的优点和缺点时,我会更新这篇文章。
class HookedImporter(importlib.abc.MetaPathFinder, importlib.abc.Loader):
def __init__(self, hooks=None):
self.hooks = hooks
def find_spec(self, name, path, target=None):
if name not in self.hooks:
return None
spec = importlib.util.spec_from_loader(name, self)
return spec
def create_module(self, spec):
# req'd in 3.6
logger.info('hooking import: %s', spec.name)
module = importlib.util._Module(spec.name)
mod = self.hooks[spec.name]
for attr in dir(mod):
if attr.startswith('__'):
continue
module.__dict__[attr] = getattr(mod, attr)
return module
def exec_module(self, module):
# module is already loaded (imported by line `import idb` above),
# so no need to re-execute.
#
# req'd in 3.6.
return
def install(self):
sys.meta_path.insert(0, self)
...稍后在某个地方...
api = mytool.from_config(...)
hooks = {
'mytool': api.mytool,
}
importer = HookedImporter(hooks=hooks)
importer.install()
with open(args.script_path, 'rb') as f:
g = {
'__name__': '__main__',
}
g.update(hooks)
exec(f.read(), g)