在飞行中组装Python模块,动态导入

我想让自己熟悉importlib钩子.我想实现一种直接导入用其他语言编写的非
pythonic文件的能力,并维护源映射,因此使用行号引发SyntaxErrors仍然会提供有意义的堆栈跟踪.

我加载外部文件的方法是组装Pythonic源,然后编译它并在所需的上下文中执行它.

我在文档中读到实现importlib.abc.SourceLoader似乎是我的选择 – 但是,唯一被调用的方法是exec_module.在那个阶段,根据我的理解,模块对象已经完全准备好了.那么为什么不调用get_source,get_data,get_code和其他?

我的存根实现:

import sys
import os

import importlib.abc
import importlib.machinery

class MyFinder(importlib.abc.MetaPathFinder):
    def __init__(self):
        pass

    def find_spec(self, fullname, path, target=None):
        print('find_spec', fullname, path, target)

        # filename = '{}.npy'.format(fullname)
        # if not os.path.exists(filename):
        #     return

        if fullname != 'foobar':
            return

        filename = 'foobar://ponyworld/foo.py'

        spec = importlib.machinery.ModuleSpec(
            name = fullname,
            loader = MyLoader(fullname, path, target),
            origin = filename,
            loader_state = 1234,
            is_package = False,
        )

        return spec

class MyLoader(importlib.abc.SourceLoader):
    def __init__(self, fullname, path, target):
        pass

    def get_data(self, path):
        print('get_data', path)

    def get_filename(self, fullname):
        print('get_filename', fullname)

    def path_stats(self, path):
        print('path_stats', path)

    def set_data(self, path, data):
        print('set_data', path, data)

    def get_code(self, fullname):
        print('get_code', fullname)

    def exec_module(self, module):
        print('exec_module', module)
        print(dir(module))

    def get_source(self, fullname):
        print('get_source', fullname)

    def is_package(self, fullname):
        print('is_package', fullname)

sys.meta_path.append(MyFinder())

# import fake module to see if it works
import foobar

最佳答案 我误解了文档并忽略了importlib.abc.SourceLoader已经为get_code,exec_module,load_module,get_source和is_package提供了实现.这些只在需要时被覆盖,只有get_data和get_filename是必需的最小值.

点赞